mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-11 02:12:21 -05:00
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
This commit is contained in:
parent
a8fb80652c
commit
ef0178cd06
10 changed files with 125 additions and 134 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Reference in a new issue