mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-10 23:36:14 -05:00
Added debug logging for 404 errors on new posts
ref https://linear.app/tryghost/issue/ONC-323 - the post model state appears to be in an odd situation when this issue occurs, the extra log context should help us determine if the bad state is occurring at the route level or inside the editor controller
This commit is contained in:
parent
5923588818
commit
618d0b130a
2 changed files with 69 additions and 3 deletions
|
@ -184,6 +184,10 @@ export default class LexicalEditorController extends Controller {
|
|||
_saveOnLeavePerformed = false;
|
||||
_previousTagNames = null; // set by setPost and _postSaved, used in hasDirtyAttributes
|
||||
|
||||
/* debug properties ------------------------------------------------------*/
|
||||
|
||||
_setPostState = null;
|
||||
|
||||
/* computed properties ---------------------------------------------------*/
|
||||
|
||||
@alias('model')
|
||||
|
@ -658,8 +662,9 @@ export default class LexicalEditorController extends Controller {
|
|||
// it as saved and performing PUT requests with no id. We want to
|
||||
// be noisy about this early to avoid data loss
|
||||
if (isNotFoundError(error)) {
|
||||
console.error(error); // eslint-disable-line no-console
|
||||
Sentry.captureException(error, {tags: {savePostTask: true}});
|
||||
const context = this._getNotFoundErrorContext();
|
||||
console.error('saveTask failed with 404', context); // eslint-disable-line no-console
|
||||
Sentry.captureException(error, {tags: {savePostTask: true}, context});
|
||||
this._showErrorAlert(prevStatus, this.post.status, 'Editor has crashed. Please copy your content and start a new post.');
|
||||
return;
|
||||
}
|
||||
|
@ -681,6 +686,13 @@ export default class LexicalEditorController extends Controller {
|
|||
}
|
||||
}
|
||||
|
||||
_getNotFoundErrorContext() {
|
||||
return {
|
||||
setPostState: this._setPostState,
|
||||
currentPostState: this.post.currentState.stateName
|
||||
};
|
||||
}
|
||||
|
||||
@task
|
||||
*beforeSaveTask(options = {}) {
|
||||
if (this.post?.isDestroyed || this.post?.isDestroying) {
|
||||
|
@ -702,7 +714,7 @@ export default class LexicalEditorController extends Controller {
|
|||
this.set('post.lexical', this.post.lexicalScratch || null);
|
||||
|
||||
// Set a default title
|
||||
if (!this.get('post.titleScratch').trim()) {
|
||||
if (!this.post.titleScratch?.trim()) {
|
||||
this.set('post.titleScratch', DEFAULT_TITLE);
|
||||
}
|
||||
|
||||
|
@ -1042,6 +1054,8 @@ export default class LexicalEditorController extends Controller {
|
|||
// reset everything ready for a new post
|
||||
this.reset();
|
||||
|
||||
this._setPostState = post.currentState.stateName;
|
||||
|
||||
this.set('post', post);
|
||||
this.backgroundLoaderTask.perform();
|
||||
|
||||
|
@ -1211,6 +1225,8 @@ export default class LexicalEditorController extends Controller {
|
|||
this._leaveConfirmed = false;
|
||||
this._saveOnLeavePerformed = false;
|
||||
|
||||
this._setPostState = null;
|
||||
|
||||
this.set('post', null);
|
||||
this.set('hasDirtyAttributes', false);
|
||||
this.set('shouldFocusTitle', false);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import EmberObject from '@ember/object';
|
||||
import RSVP from 'rsvp';
|
||||
import {authenticateSession} from 'ember-simple-auth/test-support';
|
||||
import {defineProperty} from '@ember/object';
|
||||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
|
@ -424,4 +425,53 @@ describe('Unit: Controller: lexical-editor', function () {
|
|||
expect(isDirty).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('post state debugging', function () {
|
||||
let controller, store;
|
||||
|
||||
beforeEach(async function () {
|
||||
controller = this.owner.lookup('controller:lexical-editor');
|
||||
store = this.owner.lookup('service:store');
|
||||
|
||||
// avoid any unwanted network calls
|
||||
const slugGenerator = this.owner.lookup('service:slug-generator');
|
||||
slugGenerator.generateSlug = async () => 'test-slug';
|
||||
|
||||
Object.defineProperty(controller, 'backgroundLoaderTask', {
|
||||
get: () => ({perform: () => {}})
|
||||
});
|
||||
|
||||
// avoid waiting forever for authenticate modal
|
||||
await authenticateSession();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('should call _getNotFoundErrorContext() when hitting 404 during save', async function () {
|
||||
const getErrorContextSpy = sinon.spy(controller, '_getNotFoundErrorContext');
|
||||
|
||||
const post = createPost();
|
||||
post.save = () => RSVP.reject(404);
|
||||
|
||||
controller.set('post', post);
|
||||
await controller.saveTask.perform(); // should not throw
|
||||
|
||||
expect(getErrorContextSpy.calledOnce).to.be.true;
|
||||
});
|
||||
|
||||
it('_getNotFoundErrorContext() includes setPost model state', async function () {
|
||||
const newPost = store.createRecord('post');
|
||||
controller.setPost(newPost);
|
||||
expect(controller._getNotFoundErrorContext().setPostState).to.equal('root.loaded.created.uncommitted');
|
||||
});
|
||||
|
||||
it('_getNotFoundErrorContext() includes current model state', async function () {
|
||||
const newPost = store.createRecord('post');
|
||||
controller.setPost(newPost);
|
||||
controller.post = {currentState: {stateName: 'this.is.a.test'}};
|
||||
expect(controller._getNotFoundErrorContext().currentPostState).to.equal('this.is.a.test');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue