-
Notifications
You must be signed in to change notification settings - Fork 2
Description
An idea for supporting services.
At some point in the flow, when a service is available (either automatic or user-driven, not sure). A redux event announcing a service has been found is raised:
{
type: 'SERVICE_ANNOUNCE',
payload: {
resource: { schema: 'manifest', id: 'http://.../' },
service: 'http://serviceid/'
}
}
If an extension is installed (via saga or middleware) it could listen for these events and respond if it implements the service.
function* imageServiceSaga() {
yield takeEvery('SERVICE_ANNOUNCE', function *({ payload }) {
if (isImageService(payload)) {
yield put({ type: 'IMAGE_SERVICE_IMPORT', payload });
// other instantiation logic..
// Finally let redux know its accepted
yield put({ type: 'SERVICE_ACTIVATED', {
payload: {
service: payload.service,
id: 'my-image-service',
label: 'My great image service',
}
});
}
});
}
This will go back to redux, and allow it to keep track of available extensions, and if they loaded successfully. It also allows redux to expose some methods:
- isServiceActive
- isServiceExtensionEnabled
- enableExtensionService
- disabledExtensionService
- getServiceExtensions (on resources)
Which will provide a standard model for enabling/disabling them. The extensions can also listen for these events as they get fired and react as needed.
It would be likely that services would expose UI components of some form, or at very least state selectors that can power custom components. This should all fit into this model to allow any custom service to be bootstrapped, but still known to IIIF Redux.
As for end-users creating UIs that use image services:
How the API could work
class MyComponent extends Component {
componentWillMount() {
const { id, imageServiceExists, dispatch } = this.props;
}
render() {
const { id, imageService, imageServiceActive, imageServiceExists } = this.props;
if (!imageServiceExists) {
return <div>No image available.</div>;
}
if (!imageServiceActive) {
return <div>Loading...</div>;
}
return (
<div>
<h2>Image:</h2>
<ImageServiceComponent id={imageService} target={id} />
</div>
);
}
}
export default connect(
canvasByIdSelector(api => ({
imageServiceActive: api.isServiceActive('image-service'),
imageServiceExists: api.isServiceExtensionEnabled('image-service'),
imageService: api.getServiceForExtension('image-service'),
})
))(MyComponent)
With image service maybe looking like this, using the custom selectors:
class ImageServiceComponent extends Component {
render() {
const { tileSource, thumbnail } = this.props;
<div>
<img src={thumbnail} width={200} />
{/* Maybe do something with tile source, pass to OSD? */}
</div>
}
}
export default connect(
imageServiceByIdSelector((api, props) => ({
tileSource: api.getTileSource,
thumbnail: api.getThumbnailAtSize(props.thumbnailSize || 200).
}))
)
Although it would be likely that these services would have components themselves that you can simply drop in that provide this functionality.