diff --git a/packages/classic/src/core/elements/read.js b/packages/classic/src/core/elements/read.js index 2b50893..ed4f0b1 100644 --- a/packages/classic/src/core/elements/read.js +++ b/packages/classic/src/core/elements/read.js @@ -7,12 +7,8 @@ import { read as readAction } from '../../read/actions' export default class Read extends React.Component { static propTypes = { dispatch: PropTypes.func.isRequired, - kind: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.arrayOf(PropTypes.string), - ]).isRequired, uri: PropTypes.string.isRequired, - revalidate: PropTypes.bool, + opts: PropTypes.object.isRequired, } constructor(props) { @@ -20,8 +16,8 @@ export default class Read extends React.Component { } componentDidMount() { - const { dispatch, uri, revalidate } = this.props - dispatch(readAction(uri, { revalidate })) + const { dispatch, uri, opts } = this.props + dispatch(readAction(uri, opts)) } render() { diff --git a/packages/classic/src/core/index.js b/packages/classic/src/core/index.js index c430116..e1e5cf3 100644 --- a/packages/classic/src/core/index.js +++ b/packages/classic/src/core/index.js @@ -18,6 +18,7 @@ import Read from './elements/read' import Loading from './elements/loading' import Error from './elements/error' +import * as propNames from '../propNames' /** * This is the 'default' subsystem where all 'global' registrations go to */ @@ -45,14 +46,13 @@ core.defaultSubsystems = defaultSubsystems core.read.register(core.read.default, core.read.http.httpRead) core.ui.register(['__read'], ({ element, dispatch }) => { - return ( - - ) + const opts = element + .delete('kind') + .delete('uri') + .delete(propNames.children) + .toJS() + + return }) core.ui.register(['__loading'], ({ element, dispatch }) => { return ( diff --git a/packages/classic/src/read/__tests__/read.js b/packages/classic/src/read/__tests__/read.js index 2bcc30d..24e69e6 100644 --- a/packages/classic/src/read/__tests__/read.js +++ b/packages/classic/src/read/__tests__/read.js @@ -18,7 +18,7 @@ import * as data from '../../data' import * as readActions from '../actions' import * as propNames from '../../propNames' -describe('Read Subsytem', () => { +describe('Read Subsystem', () => { const app = Subsystem.create(() => ({ name: 'app', })) @@ -70,6 +70,9 @@ describe('Read Subsytem', () => { content = kernel.query(['content']) expect(data.isExactlyOfKind('scene', content)).toBeTruthy() expect(content.get('title')).toEqual('Scene Title') + expect(content.getIn([propNames.metadata, 'request']).toJS()).toEqual( + readAction + ) }) it('handles failures', async () => { @@ -126,7 +129,10 @@ describe('Read function', () => { kernel.dispatch( action.atCursor( content, - readActions.read(content.get('uri'), { revalidate: true }) + readActions.read(content.get('uri'), { + revalidate: true, + alpha: 'beta', + }) ) ) @@ -136,6 +142,7 @@ describe('Read function', () => { 'https://netcetera.com/test.json', { revalidate: true, + alpha: 'beta', }, expect.any(Object) ) @@ -214,7 +221,7 @@ describe('Refreshing', () => { kernel.dispatch( action.atCursor( content, - readActions.readRefresh('https://netcetera.com/x.json') + readActions.readRefresh('https://netcetera.com/x.json', { foo: 'bar' }) ) ) @@ -224,7 +231,10 @@ describe('Refreshing', () => { expect(content.get('title')).toEqual('Scene Title X') expect(refresher.mock.calls[0][0]).toEqual('https://netcetera.com/x.json') - expect(refresher.mock.calls[0][1]).toMatchObject({ revalidate: true }) + expect(refresher.mock.calls[0][1]).toMatchObject({ + revalidate: true, + foo: 'bar', + }) kernel.dispatch( action.atCursor( @@ -292,6 +302,13 @@ describe('Performing reads manually', async () => { expect(result.value.getIn([propNames.metadata, 'uri'])).toEqual( 'https://netcetera.com/test.json' ) + expect( + result.value.getIn([propNames.metadata, 'request']).toJS() + ).toMatchObject({ + revalidate: true, + a: 1, + uri: 'https://netcetera.com/test.json', + }) }) function sleep(ms) { diff --git a/packages/classic/src/read/actions.js b/packages/classic/src/read/actions.js index 096b69d..02b3471 100644 --- a/packages/classic/src/read/actions.js +++ b/packages/classic/src/read/actions.js @@ -10,7 +10,19 @@ export const types = { fail: '@@skele/actions.read.fail', } -export function read(uri, opts) { +/** + * Creates a read action. + * + * @param { String } uri the URI to be read, or an ob + * @param {*} opts read options that will be passed onto the reader. + * Currently, only `revalidate` is supported + * (which instructs the reader to perform revalidation of the content). + * If used in conjuction with the standard httpRead, one controls + * the http options eventually passed to `fetch` via this argument. + * Any extra properties are allowed. These may affect specific readers. + * + */ +export function read(uri, opts = {}) { const defaults = { revalidate: false, } @@ -23,9 +35,21 @@ export function read(uri, opts) { } } -export function readRefresh(uri = undefined) { +export function readRefresh(uri = undefined, opts = undefined) { + const defaults = { + revalidate: true, + } + + let options = {} + if (opts != null) { + options = { + ...defaults, + ...opts, + } + } return { type: types.readRefresh, + ...options, uri, } } diff --git a/packages/classic/src/read/impl.js b/packages/classic/src/read/impl.js index 0a1cf63..c77739a 100644 --- a/packages/classic/src/read/impl.js +++ b/packages/classic/src/read/impl.js @@ -81,7 +81,7 @@ export function fail(element, action) { ) } -export async function performRead(context, readParams) { +export async function performRead(context, action) { const { registry, enrichment, @@ -91,7 +91,8 @@ export async function performRead(context, readParams) { const kernel = context - const { uri, opts } = readParams + const { uri, ...opts } = R.omit(['type', propNames.actionMeta], action) + const reader = registry.get(uri) || registry.get(fallback) if (reader != null) { @@ -126,7 +127,9 @@ export async function performRead(context, readParams) { } if (isOK(readResponse)) { const readValue = fromJS(readResponse.value).merge({ - [propNames.metadata]: fromJS(readResponse.meta || defaultMeta(uri)), + [propNames.metadata]: fromJS( + readResponse.meta || defaultMeta(uri) + ).merge({ request: R.omit([propNames.actionMeta], action) }), }) enhanceContext = { @@ -181,7 +184,7 @@ export async function performRead(context, readParams) { url: uri, uri, status: 999, - message: `There's no reader defined for ${pattern}. Did you forget to register a fallback reader?`, + message: `There's no reader defined for ${uri}. Did you forget to register a fallback reader?`, }, } } @@ -205,10 +208,7 @@ export async function read(context, action) { const readResponse = await time( `TIME-performRead-(${action.uri})`, performRead - )(context, { - uri: action.uri, - opts: R.pick(['revalidate'], action), - }) + )(context, action) if (isOK(readResponse)) { dispatch({ @@ -245,14 +245,22 @@ export async function read(context, action) { export async function readRefresh(context, action) { const { dispatch } = context const element = context.query() - const uri = action.uri || element.getIn([propNames.metadata, 'uri']) const readId = uuid() + let readAction + if (action.uri != null) { + readAction = action + } else { + readAction = element.getIn([propNames.metadata, 'request']).toJS() + } + invariant( - uri != null, - 'The element you are refreshing must have been loaded via a read' + readAction != null, + 'The element you are refreshing must have been loaded via a read, or you must provide an uri yourself.' ) + readAction.revalidate = flow(action, R.prop('revalidate'), R.defaultTo(true)) + context.dispatch({ ...action, readId, @@ -260,10 +268,7 @@ export async function readRefresh(context, action) { }) try { - const response = await performRead(context, { - uri: uri, - opts: { ...{ revalidate: true }, ...R.pick(['revalidate'], action) }, - }) + const response = await performRead(context, readAction) if (isOK(response)) { dispatch({ @@ -274,7 +279,7 @@ export async function readRefresh(context, action) { readValue: response.value, }) } else { - info(`Unsuccessful refreshing (read) ${uri} `, response) + info(`Unsuccessful refreshing (read) ${readAction.uri} `, response) dispatch({ ...action, @@ -284,7 +289,7 @@ export async function readRefresh(context, action) { }) } } catch (e) { - error(`Error while refreshing (read) ${uri} `, e) + error(`Error while refreshing (read) ${readAction.uri} `, e) dispatch({ ...action, diff --git a/packages/classic/src/read/index.js b/packages/classic/src/read/index.js index 8d9b328..5d99369 100644 --- a/packages/classic/src/read/index.js +++ b/packages/classic/src/read/index.js @@ -86,7 +86,7 @@ const read = SubSystem.create((system, instantiatedSubsystems) => { * * @returns Promise the read response */ - perform: (uri, opts = {}) => impl.performRead(system, { uri, opts }), + perform: (uri, opts = {}) => impl.performRead(system, { ...opts, uri }), } })