From ef0178cd06a7515bddf7a2b307862a28929ca5a5 Mon Sep 17 00:00:00 2001
From: Kevin Ansfield <kevin@lookingsideways.co.uk>
Date: Fri, 7 Oct 2022 18:39:34 +0100
Subject: [PATCH] Refactored posts and pages controllers to Octane patterns

refs https://github.com/TryGhost/Ghost/issues/14101

- migrated to full native class syntax
- removed loading of snippets as they are not needed on post lists (they are needed on the editor screen which does it's own loading)
- removed `access` query param definition leftover from earlier development
- removed use of `{{action}}` in associated templates
---
 ghost/admin/.lint-todo                       |  20 ++++
 ghost/admin/app/controllers/pages-loading.js |   6 +-
 ghost/admin/app/controllers/pages.js         |  15 +--
 ghost/admin/app/controllers/posts-loading.js |  58 +++++-----
 ghost/admin/app/controllers/posts.js         | 111 ++++++++-----------
 ghost/admin/app/routes/posts.js              |   9 +-
 ghost/admin/app/templates/pages-loading.hbs  |  10 +-
 ghost/admin/app/templates/pages.hbs          |  10 +-
 ghost/admin/app/templates/posts-loading.hbs  |  10 +-
 ghost/admin/app/templates/posts.hbs          |  10 +-
 10 files changed, 125 insertions(+), 134 deletions(-)

diff --git a/ghost/admin/.lint-todo b/ghost/admin/.lint-todo
index d645da8e1a..5a7c1ec4d1 100644
--- a/ghost/admin/.lint-todo
+++ b/ghost/admin/.lint-todo
@@ -978,3 +978,23 @@ add|ember-template-lint|no-action|47|49|47|49|18f748b67f9fe570b08c7a1c1d99114f31
 add|ember-template-lint|no-action|51|52|51|52|4d50f3b33a672c365969169a4c0ca14cf83fe39c|1665014400000|1675386000000|1680566400000|app/components/settings/navigation/nav-item.hbs
 add|ember-template-lint|no-passed-in-event-handlers|20|12|20|12|4069dec45ac2a31d440780c914b2307ad1c6ea5f|1665014400000|1675386000000|1680566400000|app/components/settings/navigation/nav-item.hbs
 add|ember-template-lint|no-passed-in-event-handlers|21|12|21|12|e53f64794fdd0fe8c8b027d1831942d7c78c503b|1665014400000|1675386000000|1680566400000|app/components/settings/navigation/nav-item.hbs
+remove|ember-template-lint|no-action|10|30|10|30|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/pages-loading.hbs
+remove|ember-template-lint|no-action|13|36|13|36|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/pages-loading.hbs
+remove|ember-template-lint|no-action|16|32|16|32|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/pages-loading.hbs
+remove|ember-template-lint|no-action|19|29|19|29|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/pages-loading.hbs
+remove|ember-template-lint|no-action|22|31|22|31|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/pages-loading.hbs
+remove|ember-template-lint|no-action|10|30|10|30|7f6ae6475e94edfe22b59577ca52d10ec66835af|1662681600000|1673053200000|1678237200000|app/templates/pages.hbs
+remove|ember-template-lint|no-action|13|36|13|36|addf24b8fbd6518060e412ec8b95309a05254988|1662681600000|1673053200000|1678237200000|app/templates/pages.hbs
+remove|ember-template-lint|no-action|16|32|16|32|5bf020bb7cafdcfbcf809310232be927a9f1b2e4|1662681600000|1673053200000|1678237200000|app/templates/pages.hbs
+remove|ember-template-lint|no-action|19|29|19|29|e3023c525990c1f8d1a30aa6ff20eb3bad8ec53b|1662681600000|1673053200000|1678237200000|app/templates/pages.hbs
+remove|ember-template-lint|no-action|22|31|22|31|cbf4e21da2010b9af11294f458ef2ad40374d4f0|1662681600000|1673053200000|1678237200000|app/templates/pages.hbs
+remove|ember-template-lint|no-action|10|30|10|30|7f6ae6475e94edfe22b59577ca52d10ec66835af|1663027200000|1673398800000|1678582800000|app/templates/posts.hbs
+remove|ember-template-lint|no-action|13|36|13|36|addf24b8fbd6518060e412ec8b95309a05254988|1663027200000|1673398800000|1678582800000|app/templates/posts.hbs
+remove|ember-template-lint|no-action|16|32|16|32|5bf020bb7cafdcfbcf809310232be927a9f1b2e4|1663027200000|1673398800000|1678582800000|app/templates/posts.hbs
+remove|ember-template-lint|no-action|19|29|19|29|e3023c525990c1f8d1a30aa6ff20eb3bad8ec53b|1663027200000|1673398800000|1678582800000|app/templates/posts.hbs
+remove|ember-template-lint|no-action|22|31|22|31|cbf4e21da2010b9af11294f458ef2ad40374d4f0|1663027200000|1673398800000|1678582800000|app/templates/posts.hbs
+remove|ember-template-lint|no-action|9|30|9|30|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/posts-loading.hbs
+remove|ember-template-lint|no-action|12|36|12|36|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/posts-loading.hbs
+remove|ember-template-lint|no-action|15|32|15|32|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/posts-loading.hbs
+remove|ember-template-lint|no-action|18|29|18|29|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/posts-loading.hbs
+remove|ember-template-lint|no-action|21|31|21|31|796968d082daba388ca19e97d45c7278d1076f04|1662681600000|1673053200000|1678237200000|app/templates/posts-loading.hbs
diff --git a/ghost/admin/app/controllers/pages-loading.js b/ghost/admin/app/controllers/pages-loading.js
index f60e362212..7ac73787d5 100644
--- a/ghost/admin/app/controllers/pages-loading.js
+++ b/ghost/admin/app/controllers/pages-loading.js
@@ -1,13 +1,9 @@
 import PostsLoadingController from './posts-loading';
-import classic from 'ember-classic-decorator';
 import {inject as controller} from '@ember/controller';
 import {inject as service} from '@ember/service';
 
-/* eslint-disable ghost/ember/alias-model-in-controller */
-@classic
 export default class PagesLoadingController extends PostsLoadingController {
-    @controller('pages')
-        postsController;
+    @controller('pages') postsController;
 
     @service ui;
 }
diff --git a/ghost/admin/app/controllers/pages.js b/ghost/admin/app/controllers/pages.js
index 7c2b86017a..a999bf8fd5 100644
--- a/ghost/admin/app/controllers/pages.js
+++ b/ghost/admin/app/controllers/pages.js
@@ -1,6 +1,6 @@
 import PostsController from './posts';
-import classic from 'ember-classic-decorator';
 import {action} from '@ember/object';
+import {inject as service} from '@ember/service';
 
 const TYPES = [{
     name: 'All pages',
@@ -30,17 +30,14 @@ const ORDERS = [{
     value: 'updated_at desc'
 }];
 
-/* eslint-disable ghost/ember/alias-model-in-controller */
-@classic
 export default class PagesController extends PostsController {
-    init() {
-        super.init(...arguments);
-        this.availableTypes = TYPES;
-        this.availableOrders = ORDERS;
-    }
+    @service router;
+
+    availableTypes = TYPES;
+    availableOrders = ORDERS;
 
     @action
     openEditor(page) {
-        this.transitionToRoute('editor.edit', 'page', page.get('id'));
+        this.router.transitionTo('editor.edit', 'page', page.get('id'));
     }
 }
diff --git a/ghost/admin/app/controllers/posts-loading.js b/ghost/admin/app/controllers/posts-loading.js
index 744bf5f8c0..5dd8295638 100644
--- a/ghost/admin/app/controllers/posts-loading.js
+++ b/ghost/admin/app/controllers/posts-loading.js
@@ -1,45 +1,49 @@
 import Controller, {inject as controller} from '@ember/controller';
-import classic from 'ember-classic-decorator';
-import {readOnly} from '@ember/object/computed';
 import {inject as service} from '@ember/service';
-
-/* eslint-disable ghost/ember/alias-model-in-controller */
-@classic
 export default class PostsLoadingController extends Controller {
-    @controller('posts')
-        postsController;
+    @controller('posts') postsController;
 
     @service session;
     @service ui;
     @service config;
 
-    @readOnly('postsController.availableTypes')
-        availableTypes;
+    get availableTypes() {
+        return this.postsController.availableTypes;
+    }
 
-    @readOnly('postsController.selectedType')
-        selectedType;
+    get selectedType() {
+        return this.postsController.selectedType;
+    }
 
-    @readOnly('postsController.selectedVisibility')
-        selectedVisibility;
+    get selectedVisibility() {
+        return this.postsController.selectedVisibility;
+    }
 
-    @readOnly('postsController.availableVisibilities')
-        availableVisibilities;
+    get availableVisibilities() {
+        return this.postsController.availableVisibilities;
+    }
 
-    @readOnly('postsController.availableTags')
-        availableTags;
+    get availableTags() {
+        return this.postsController.availableTags;
+    }
 
-    @readOnly('postsController.selectedTag')
-        selectedTag;
+    get selectedTag() {
+        return this.postsController.selectedTag;
+    }
 
-    @readOnly('postsController.availableAuthors')
-        availableAuthors;
+    get availableAuthors() {
+        return this.postsController.availableAuthors;
+    }
 
-    @readOnly('postsController.selectedAuthor')
-        selectedAuthor;
+    get selectedAuthor() {
+        return this.postsController.selectedAuthor;
+    }
 
-    @readOnly('postsController.availableOrders')
-        availableOrders;
+    get availableOrders() {
+        return this.postsController.availableOrders;
+    }
 
-    @readOnly('postsController.selectedOrder')
-        selectedOrder;
+    get selectedOrder() {
+        return this.postsController.selectedOrder;
+    }
 }
diff --git a/ghost/admin/app/controllers/posts.js b/ghost/admin/app/controllers/posts.js
index ece9e58d2c..1e9c4d0158 100644
--- a/ghost/admin/app/controllers/posts.js
+++ b/ghost/admin/app/controllers/posts.js
@@ -1,9 +1,8 @@
 import Controller from '@ember/controller';
-import classic from 'ember-classic-decorator';
 import {DEFAULT_QUERY_PARAMS} from 'ghost-admin/helpers/reset-query-params';
-import {action, computed, get} from '@ember/object';
-import {alias} from '@ember/object/computed';
+import {action} from '@ember/object';
 import {inject as service} from '@ember/service';
+import {tracked} from '@glimmer/tracking';
 
 const TYPES = [{
     name: 'All posts',
@@ -47,32 +46,38 @@ const ORDERS = [{
     value: 'updated_at desc'
 }];
 
-@classic
 export default class PostsController extends Controller {
+    @service config;
     @service feature;
+    @service router;
     @service session;
     @service store;
-    @service settings;
-    @service config;
 
-    // default values for these are set in `init` and defined in `helpers/reset-query-params`
-    queryParams = ['type', 'access', 'author', 'tag', 'order'];
+    // default values for these are set in constructor and defined in `helpers/reset-query-params`
+    queryParams = ['type', 'visibility', 'author', 'tag', 'order'];
+
+    @tracked type = null;
+    @tracked visibility = null;
+    @tracked author = null;
+    @tracked tag = null;
+    @tracked order = null;
+
+    availableTypes = TYPES;
+    availableVisibilities = VISIBILITIES;
+    availableOrders = ORDERS;
+
+    _availableTags = this.store.peekAll('tag');
+    _availableAuthors = this.store.peekAll('user');
 
     _hasLoadedTags = false;
     _hasLoadedAuthors = false;
-    _hasLoadedSnippets = false;
-    availableTypes = null;
-    availableVisibilities = null;
-    availableOrders = null;
 
-    init() {
-        super.init(...arguments);
-        this.availableTypes = TYPES;
-        this.availableOrders = ORDERS;
-        this.availableVisibilities = VISIBILITIES;
-        this.setProperties(DEFAULT_QUERY_PARAMS.posts);
+    constructor() {
+        super(...arguments);
 
-        if (this.feature.get('emailAnalytics') && !this.availableOrders.findBy('name', 'Open rate')) {
+        Object.assign(this, DEFAULT_QUERY_PARAMS.posts);
+
+        if (this.feature.emailAnalytics && !this.availableOrders.findBy('name', 'Open rate')) {
             this.availableOrders.push({
                 name: 'Open rate',
                 value: 'email.open_rate desc'
@@ -80,74 +85,55 @@ export default class PostsController extends Controller {
         }
     }
 
-    @alias('model')
-        postsInfinityModel;
+    get postsInfinityModel() {
+        return this.model;
+    }
 
-    @computed('type', 'author', 'tag')
     get showingAll() {
-        let {type, author, tag, visibility} = this;
+        const {type, author, tag, visibility} = this;
 
         return !type && !visibility && !author && !tag;
     }
 
-    @computed('type')
     get selectedType() {
-        let types = this.availableTypes;
-        return types.findBy('value', this.type) || {value: '!unknown'};
+        return this.availableTypes.findBy('value', this.type) || {value: '!unknown'};
     }
 
-    @computed('visibility')
     get selectedVisibility() {
-        let visibilities = this.availableVisibilities;
-        return visibilities.findBy('value', this.visibility) || {value: '!unknown'};
+        return this.availableVisibilities.findBy('value', this.visibility) || {value: '!unknown'};
     }
 
-    @computed('order')
     get selectedOrder() {
-        let orders = this.availableOrders;
-        return orders.findBy('value', this.order) || {value: '!unknown'};
+        return this.availableOrders.findBy('value', this.order) || {value: '!unknown'};
     }
 
-    @computed
-    get _availableTags() {
-        return this.store.peekAll('tag');
-    }
-
-    @computed('_availableTags.[]')
     get availableTags() {
-        let tags = this._availableTags
+        const tags = this._availableTags
             .filter(tag => tag.get('id') !== null)
             .sort((tagA, tagB) => tagA.name.localeCompare(tagB.name, undefined, {ignorePunctuation: true}));
-        let options = tags.toArray();
-        options.unshiftObject({name: 'All tags', slug: null});
+
+        const options = tags.toArray();
+        options.unshift({name: 'All tags', slug: null});
 
         return options;
     }
 
-    @computed('tag', '_availableTags.[]')
     get selectedTag() {
-        let tag = this.tag;
-        let tags = this.availableTags;
+        const tag = this.tag;
+        const tags = this.availableTags;
 
         return tags.findBy('slug', tag) || {slug: '!unknown'};
     }
 
-    @computed
-    get _availableAuthors() {
-        return this.store.peekAll('user');
-    }
-
-    @computed('_availableAuthors.[]')
     get availableAuthors() {
-        let authors = this._availableAuthors;
-        let options = authors.toArray();
+        const authors = this._availableAuthors;
+        const options = authors.toArray();
 
-        options.unshiftObject({name: 'All authors', slug: null});
+        options.unshift({name: 'All authors', slug: null});
 
         return options;
     }
 
-    @computed('author', 'availableAuthors.[]')
     get selectedAuthor() {
         let author = this.author;
         let authors = this.availableAuthors;
@@ -155,38 +141,33 @@ export default class PostsController extends Controller {
         return authors.findBy('slug', author) || {slug: '!unknown'};
     }
 
-    @computed
-    get snippets() {
-        return this.store.peekAll('snippet');
-    }
-
     @action
     changeType(type) {
-        this.set('type', get(type, 'value'));
+        this.type = type.value;
     }
 
     @action
     changeVisibility(visibility) {
-        this.set('visibility', get(visibility, 'value'));
+        this.visibility = visibility.value;
     }
 
     @action
     changeAuthor(author) {
-        this.set('author', get(author, 'slug'));
+        this.author = author.slug;
     }
 
     @action
     changeTag(tag) {
-        this.set('tag', get(tag, 'slug'));
+        this.tag = tag.slug;
     }
 
     @action
     changeOrder(order) {
-        this.set('order', get(order, 'value'));
+        this.order = order.value;
     }
 
     @action
     openEditor(post) {
-        this.transitionToRoute('editor.edit', 'post', post.get('id'));
+        this.router.transitionTo('editor.edit', 'post', post.id);
     }
 }
diff --git a/ghost/admin/app/routes/posts.js b/ghost/admin/app/routes/posts.js
index e3f6e92e72..e2a9070c81 100644
--- a/ghost/admin/app/routes/posts.js
+++ b/ghost/admin/app/routes/posts.js
@@ -12,7 +12,6 @@ export default class PostsRoute extends AuthenticatedRoute {
     queryParams = {
         type: {refreshModel: true},
         visibility: {refreshModel: true},
-        access: {refreshModel: true},
         author: {refreshModel: true},
         tag: {refreshModel: true},
         order: {refreshModel: true}
@@ -79,7 +78,7 @@ export default class PostsRoute extends AuthenticatedRoute {
         return this.infinity.model(this.modelName, paginationSettings);
     }
 
-    // trigger a background load of all tags, authors, and snipps for use in filter dropdowns and card menu
+    // trigger a background load of all tags and authors for use in filter dropdowns
     setupController(controller) {
         super.setupController(...arguments);
 
@@ -94,12 +93,6 @@ export default class PostsRoute extends AuthenticatedRoute {
                 controller._hasLoadedAuthors = true;
             });
         }
-
-        if (!controller._hasLoadedSnippets) {
-            this.store.query('snippet', {limit: 'all'}).then(() => {
-                controller._hasLoadedSnippets = true;
-            });
-        }
     }
 
     @action
diff --git a/ghost/admin/app/templates/pages-loading.hbs b/ghost/admin/app/templates/pages-loading.hbs
index 65193786fb..a12d36a512 100644
--- a/ghost/admin/app/templates/pages-loading.hbs
+++ b/ghost/admin/app/templates/pages-loading.hbs
@@ -7,19 +7,19 @@
                 @currentUser={{this.session.user}}
                 @selectedType={{this.selectedType}}
                 @availableTypes={{this.availableTypes}}
-                @onTypeChange={{action (mut this.k)}}
+                @onTypeChange={{optional null}}
                 @selectedVisibility={{this.selectedVisibility}}
                 @availableVisibilities={{this.availableVisibilities}}
-                @onVisibilityChange={{action (mut this.k)}}
+                @onVisibilityChange={{optional null}}
                 @selectedAuthor={{this.selectedAuthor}}
                 @availableAuthors={{this.availableAuthors}}
-                @onAuthorChange={{action (mut this.k)}}
+                @onAuthorChange={{optional null}}
                 @selectedTag={{this.selectedTag}}
                 @availableTags={{this.availableTags}}
-                @onTagChange={{action (mut this.k)}}
+                @onTagChange={{optional null}}
                 @selectedOrder={{this.selectedOrder}}
                 @availableOrders={{this.availableOrders}}
-                @onOrderChange={{action (mut this.k)}}
+                @onOrderChange={{optional null}}
             />
 
             <LinkTo @route="editor.new" @model="page" class="gh-btn gh-btn-primary view-actions-top-row" data-test-new-page-button={{true}}><span>New page</span></LinkTo>
diff --git a/ghost/admin/app/templates/pages.hbs b/ghost/admin/app/templates/pages.hbs
index bacb6a0e8a..4efd8b74a8 100644
--- a/ghost/admin/app/templates/pages.hbs
+++ b/ghost/admin/app/templates/pages.hbs
@@ -7,19 +7,19 @@
                 @currentUser={{this.session.user}}
                 @selectedType={{this.selectedType}}
                 @availableTypes={{this.availableTypes}}
-                @onTypeChange={{action "changeType"}}
+                @onTypeChange={{this.changeType}}
                 @selectedVisibility={{this.selectedVisibility}}
                 @availableVisibilities={{this.availableVisibilities}}
-                @onVisibilityChange={{action "changeVisibility"}}
+                @onVisibilityChange={{this.changeVisibility}}
                 @selectedAuthor={{this.selectedAuthor}}
                 @availableAuthors={{this.availableAuthors}}
-                @onAuthorChange={{action "changeAuthor"}}
+                @onAuthorChange={{this.changeAuthor}}
                 @selectedTag={{this.selectedTag}}
                 @availableTags={{this.availableTags}}
-                @onTagChange={{action "changeTag"}}
+                @onTagChange={{this.changeTag}}
                 @selectedOrder={{this.selectedOrder}}
                 @availableOrders={{this.availableOrders}}
-                @onOrderChange={{action "changeOrder"}}
+                @onOrderChange={{this.changeOrder}}
             />
 
             <LinkTo @route="editor.new" @model="page" class="gh-btn gh-btn-primary view-actions-top-row" data-test-new-page-button={{true}}><span>New page</span></LinkTo>
diff --git a/ghost/admin/app/templates/posts-loading.hbs b/ghost/admin/app/templates/posts-loading.hbs
index ac55bcac85..ba1d3a65e0 100644
--- a/ghost/admin/app/templates/posts-loading.hbs
+++ b/ghost/admin/app/templates/posts-loading.hbs
@@ -6,19 +6,19 @@
                 @currentUser={{this.session.user}}
                 @selectedType={{this.selectedType}}
                 @availableTypes={{this.availableTypes}}
-                @onTypeChange={{action (mut this.k)}}
+                @onTypeChange={{optional null}}
                 @selectedVisibility={{this.selectedVisibility}}
                 @availableVisibilities={{this.availableVisibilities}}
-                @onVisibilityChange={{action (mut this.k)}}
+                @onVisibilityChange={{optional null}}
                 @selectedAuthor={{this.selectedAuthor}}
                 @availableAuthors={{this.availableAuthors}}
-                @onAuthorChange={{action (mut this.k)}}
+                @onAuthorChange={{optional null}}
                 @selectedTag={{this.selectedTag}}
                 @availableTags={{this.availableTags}}
-                @onTagChange={{action (mut this.k)}}
+                @onTagChange={{optional null}}
                 @selectedOrder={{this.selectedOrder}}
                 @availableOrders={{this.availableOrders}}
-                @onOrderChange={{action (mut this.k)}}
+                @onOrderChange={{optional null}}
             />
 
             <LinkTo @route="editor.new" @model="post" class="gh-btn gh-btn-primary view-actions-top-row" data-test-new-post-button={{true}}><span>New post</span></LinkTo>
diff --git a/ghost/admin/app/templates/posts.hbs b/ghost/admin/app/templates/posts.hbs
index f3194860a8..dcc25abf98 100644
--- a/ghost/admin/app/templates/posts.hbs
+++ b/ghost/admin/app/templates/posts.hbs
@@ -7,19 +7,19 @@
                 @currentUser={{this.session.user}}
                 @selectedType={{this.selectedType}}
                 @availableTypes={{this.availableTypes}}
-                @onTypeChange={{action "changeType"}}
+                @onTypeChange={{this.changeType}}
                 @selectedVisibility={{this.selectedVisibility}}
                 @availableVisibilities={{this.availableVisibilities}}
-                @onVisibilityChange={{action "changeVisibility"}}
+                @onVisibilityChange={{this.changeVisibility}}
                 @selectedAuthor={{this.selectedAuthor}}
                 @availableAuthors={{this.availableAuthors}}
-                @onAuthorChange={{action "changeAuthor"}}
+                @onAuthorChange={{this.changeAuthor}}
                 @selectedTag={{this.selectedTag}}
                 @availableTags={{this.availableTags}}
-                @onTagChange={{action "changeTag"}}
+                @onTagChange={{this.changeTag}}
                 @selectedOrder={{this.selectedOrder}}
                 @availableOrders={{this.availableOrders}}
-                @onOrderChange={{action "changeOrder"}}
+                @onOrderChange={{this.changeOrder}}
             />
 
             <LinkTo @route="editor.new" @model="post" class="gh-btn gh-btn-primary view-actions-top-row" data-test-new-post-button={{true}}><span>New post</span></LinkTo>