Add ember-data error types; Ember.ViewUtils.isSimpleClick. (#22924)

This commit is contained in:
Chris Krycho
2018-01-17 10:52:29 -07:00
committed by Wesley Wigham
parent 2037b3b9ba
commit 8b902e076f
7 changed files with 138 additions and 13 deletions

View File

@@ -208,7 +208,7 @@ declare module "ember-data" {
* subclasses are used to indicate specific error states. The following
* subclasses are provided:
*/
class AdapterError {}
class AdapterError extends Ember.Object {}
/**
* A `DS.InvalidError` is used by an adapter to signal the external API
* was unable to process a request because the content was not
@@ -218,27 +218,29 @@ declare module "ember-data" {
* transition to the `invalid` state and the errors will be set to the
* `errors` property on the record.
*/
class InvalidError {}
class InvalidError extends AdapterError {
constructor(errors: any[]);
}
/**
* A `DS.TimeoutError` is used by an adapter to signal that a request
* to the external API has timed out. I.e. no response was received from
* the external API within an allowed time period.
*/
class TimeoutError {}
class TimeoutError extends AdapterError {}
/**
* A `DS.AbortError` is used by an adapter to signal that a request to
* the external API was aborted. For example, this can occur if the user
* navigates away from the current page after a request to the external API
* has been initiated but before a response has been received.
*/
class AbortError {}
class AbortError extends AdapterError {}
/**
* A `DS.UnauthorizedError` equates to a HTTP `401 Unauthorized` response
* status. It is used by an adapter to signal that a request to the external
* API was rejected because authorization is required and has failed or has not
* yet been provided.
*/
class UnauthorizedError {}
class UnauthorizedError extends AdapterError {}
/**
* A `DS.ForbiddenError` equates to a HTTP `403 Forbidden` response status.
* It is used by an adapter to signal that a request to the external API was
@@ -246,13 +248,13 @@ declare module "ember-data" {
* provided and is valid, then the authenticated user does not have the
* necessary permissions for the request.
*/
class ForbiddenError {}
class ForbiddenError extends AdapterError {}
/**
* A `DS.NotFoundError` equates to a HTTP `404 Not Found` response status.
* It is used by an adapter to signal that a request to the external API
* was rejected because the resource could not be found on the API.
*/
class NotFoundError {}
class NotFoundError extends AdapterError {}
/**
* A `DS.ConflictError` equates to a HTTP `409 Conflict` response status.
* It is used by an adapter to indicate that the request could not be processed
@@ -260,13 +262,13 @@ declare module "ember-data" {
* creating a record with a client generated id but that id is already known
* to the external API.
*/
class ConflictError {}
class ConflictError extends AdapterError {}
/**
* A `DS.ServerError` equates to a HTTP `500 Internal Server Error` response
* status. It is used by the adapter to indicate that a request has failed
* because of an error in the external API.
*/
class ServerError {}
class ServerError extends AdapterError {}
/**
* Holds validation errors for a given record, organized by attribute names.
*/

View File

@@ -0,0 +1,106 @@
import Ember from 'ember';
import DS from 'ember-data';
import { assertType } from './lib/assert';
const { AdapterError } = DS;
// https://emberjs.com/api/ember-data/2.16/classes/DS.AdapterError
const MaintenanceError = DS.AdapterError.extend({
message: 'Down for maintenance.',
});
const maintenanceError = new MaintenanceError();
assertType<DS.AdapterError>(maintenanceError);
// https://emberjs.com/api/ember-data/2.16/classes/DS.InvalidError
const anInvalidError = new DS.InvalidError([
{
detail: 'Must be unique',
source: { pointer: '/data/attributes/title' },
},
{
detail: 'Must not be blank',
source: { pointer: '/data/attributes/content' },
},
]);
// https://emberjs.com/api/ember-data/2.16/classes/DS.TimeoutError
const { TimeoutError } = DS;
const timedOut = Ember.Route.extend({
actions: {
error(error: any, transition: any) {
if (error instanceof TimeoutError) {
// alert the user
alert('Are you still connected to the internet?');
return;
}
// ...other error handling logic
},
},
});
// This is technically private, but publicly exposed for APIs to use. We just
// check that it is a proper subclass of `AdapterError`.
// https://emberjs.com/api/ember-data/2.16/classes/DS.AbortError
// https://github.com/emberjs/data/blob/v2.16.0/addon/-private/adapters/errors.js#L206-L216
const { AbortError } = DS;
assertType<typeof AdapterError>(AbortError);
// https://emberjs.com/api/ember-data/2.16/classes/DS.UnauthorizedError
const { UnauthorizedError } = DS;
assertType<typeof AdapterError>(UnauthorizedError);
const unauthorized = Ember.Route.extend({
actions: {
error(error: any, transition: any) {
if (error instanceof UnauthorizedError) {
// go to the sign in route
this.transitionTo('login');
return;
}
// ...other error handling logic
},
},
});
// This is technically private, but publicly exposed for APIs to use. We just
// check that it is a proper subclass of `AdapterError`.
// https://emberjs.com/api/ember-data/2.16/classes/DS.ForbiddenError
// https://github.com/emberjs/data/blob/v2.16.0/addon/-private/adapters/errors.js#L253-L263
const { ForbiddenError } = DS;
assertType<typeof AdapterError>(ForbiddenError);
// https://emberjs.com/api/ember-data/2.16/classes/DS.NotFoundError
const { NotFoundError } = DS;
assertType<typeof AdapterError>(NotFoundError);
const notFound = Ember.Route.extend({
model(params: { post_id: string }): any {
return this.get('store').findRecord('post', params.post_id);
},
actions: {
error(error: any, transition: any): any {
if (error instanceof NotFoundError) {
// redirect to a list of all posts instead
this.transitionTo('posts');
} else {
// otherwise let the error bubble
return true;
}
},
},
});
// This is technically private, but publicly exposed for APIs to use. We just
// check that it is a proper subclass of `AdapterError`.
// https://emberjs.com/api/ember-data/2.16/classes/DS.ConflictError
// https://github.com/emberjs/data/blob/v2.16.0/addon/-private/adapters/errors.js#L303-L313
const { ConflictError } = DS;
assertType<typeof AdapterError>(ConflictError);
// This is technically private, but publicly exposed for APIs to use. We just
// check that it is a proper subclass of `AdapterError`.
// https://emberjs.com/api/ember-data/2.16/classes/DS.ServerError
// https://github.com/emberjs/data/blob/v2.16.0/addon/-private/adapters/errors.js#L315-L323
const { ServerError } = DS;
assertType<typeof AdapterError>(ServerError);

View File

@@ -28,6 +28,7 @@
"test/has-many.ts",
"test/belongs-to.ts",
"test/record-reference.ts",
"test/injections.ts"
"test/injections.ts",
"test/error.ts"
]
}

View File

@@ -1846,7 +1846,7 @@ declare module 'ember' {
be useful, for instance, for retrieving async code from
the server that is required to enter a route.
*/
beforeModel(transition: Transition): Rsvp.Promise<any>;
beforeModel(transition: Transition): any;
/**
* Returns the controller for a particular route or name.
@@ -2207,7 +2207,9 @@ declare module 'ember' {
actionContext: any;
}
const ViewTargetActionSupport: Mixin<ViewTargetActionSupport>;
const ViewUtils: {}; // TODO: define interface
const ViewUtils: {
isSimpleClick(event: Event): boolean;
};
// FYI - RSVP source comes from https://github.com/tildeio/rsvp.js/blob/master/lib/rsvp/promise.js
const RSVP: typeof Rsvp;

View File

@@ -85,3 +85,11 @@ Route.extend({
this.controllerFor('application').set('model', model);
},
});
class RouteUsingClass extends Route.extend({
randomProperty: 'the .extend + extends bit type-checks properly',
}) {
beforeModel(this: RouteUsingClass) {
return 'beforeModel can return anything, not just promises';
}
}

View File

@@ -0,0 +1,5 @@
import Ember from 'ember';
import { assertType } from './lib/assert';
const { ViewUtils: { isSimpleClick } } = Ember;
assertType<boolean>(isSimpleClick(new Event('wat')));

View File

@@ -44,6 +44,7 @@
"test/run.ts",
"test/test.ts",
"test/controller.ts",
"test/route.ts"
"test/route.ts",
"test/view-utils.ts"
]
}