Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move manifesto out of the store state #1663

Closed
aeschylus opened this issue Jan 18, 2019 · 13 comments
Closed

move manifesto out of the store state #1663

aeschylus opened this issue Jan 18, 2019 · 13 comments

Comments

@aeschylus
Copy link
Collaborator

No description provided.

@mejackreed
Copy link
Collaborator

mejackreed commented Jan 18, 2019

@jbaiter brought up revisiting looking at the implementation in https://github.com/stephenwf/iiif-redux

@jbaiter
Copy link
Collaborator

jbaiter commented Jan 23, 2019

It does look like it would take care of quite a lot for us: https://github.com/stephenwf/iiif-redux/blob/master/CONCEPTS.md
The normalized state concept is pretty similar to what @charbugs and @christopher-johnson have suggested, I think. And we have also looked at the reselect library already, which it uses, so it seems like it might be a good fit.

@mejackreed
Copy link
Collaborator

I've tried to implement it. One problem that I have run into so far is that the library is yet unreleased as a package. @stephenwf are there plans to release iiif-redux?

One other question I had was, to what extent could we extend it?

@stephenwf
Copy link

tl;dr it has extensions points for the guts, lets you add custom reducers, middleware and sagas so you can continue to use redux with it. Library need some API / usability work before release (soon).

I did some research a while back, to see what Mirador actually extracts from IIIF resources, to get an idea of what would be useful in terms of an API. This is my notes, some of the points on it I can't remember the context of them, but thought I'd chuck it in.

  • Manifest
    • thumbnail
    • version
    • structures / ranges
    • creating fake manifest wrappers
    • search within service (endpoint)
    • label
    • viewing direction
  • Collection
    • version
    • manifests
    • nested collections
  • Annotations
    • Annotated by
    • annotation endpoint (custom)
    • textual content
    • tags
    • selectors (box, svg, point)
    • motivations

I've highlighted some gaps in italics that IIIF redux does not cover yet (and may not cover).

I also created a frames extension internally to see how easy it was to extend with custom reducers/state and sagas. I think it went quite well. The frames demo was in part to test the waters on having multiple IIIF resources (and the state like current canvas, viewport etc) running at one time.

The "frames" demo isn't aware of any user interface, but it is made to be extended itself. I created a proof of concept extensions around frames to mimic chrome tabs (source | demo) with some simple wrappers around the actions to create new actions more specific to the application (like createNewTab, updateSortOrder).

That would be the sort of extension points for the guts of the library, if you chose to use it, extending and wrapping the primitive actions and selectors into specific concrete actions to match the viewer.

As for extending with custom state/actions/sagas, the library does (or will?) export a createStore similar to Redux itself, so you can simple pass in state, reducers, sagas, middleware in the same way you use redux. The library "claims" a few paths in the state, but should be easy enough to work around. (source)

I do want to release an initial version of the library, now that Presentation 3 Alpha has been implemented. I still need to bring some parity to the Presentation 2 and 3 APIs so you can use the same selectors on either resource, but I'm more than happy to expedite development of that if you'd like to prototype.

@christopher-johnson
Copy link
Contributor

While I realize that there are concerns with implementing a server, I need to say that the iiif-redux approach seems very complex compared with GraphQL. Apollo Server also supports paging and handles the remote async transport server side. Basically, GraphQL allows you to provide criteria to get exactly what you need from a complex/deeply nested object, just like SQL. For example, here is a query for a canvas using the manifestId and the canvasId.

query { canvas(manifestId: "https://iiif.bodleian.ox.ac.uk/iiif/manifest/d3a54f05-b2a7-4a3b-a181-fed761e41d67.json", 
canvasId: "https://iiif.bodleian.ox.ac.uk/iiif/canvas/d3a54f05-b2a7-4a3b-a181-fed761e41d67.json"),
            {id, label, width, height}
          }

which returns this object:

{
  "data": {
    "canvas": {
      "id": "https://iiif.bodleian.ox.ac.uk/iiif/canvas/d3a54f05-b2a7-4a3b-a181-fed761e41d67.json",
      "label": "Whole page",
      "width": 5822,
      "height": 8544
    }
  }
}

The server requires a resolver method for the query type which is like reducer. This is the resolver for a canvas

The task for the client becomes relatively simple. Get specific values from JSON objects and pass them as properties to rendering components. For me, it is not clear what all of the redux machinery actually brings to the table other than being able to serialize state. I should also be possible to use redux and the apollo client together.

@stephenwf
Copy link

@christopher-johnson There is a proof of concept running GraphQL schema on the client side, as an abstraction around IIIF Redux and the selectors. Pull request is here: stephenwf/iiif-redux#231

Some bits from the PR:

There's definite potential in IIIF over GraphQL (server or client) and will really make developing with it much nicer. It is however either heavy on the client side, or requires a server.

On the point of complexity, IIIF redux is very very verbose to use just now, but just like writing any GraphQL query, or SQL query, you write it once and use it many times. Abstract common sets of fields for resources and build up a library of selectors.

@christopher-johnson
Copy link
Contributor

@stephenwf Nice work! Interesting discussion on the PR as well. Do we have sufficient motivation here to seek out a solution in the community to the server question?

@jbaiter
Copy link
Collaborator

jbaiter commented Jan 24, 2019

While I realize that there are concerns with implementing a server

I think there's more than just concerns, it's a complete deal breaker for a lot of Mirador use cases and goes against the whole IIIF philosophy of keeping it simple and easy to deploy.
While I can see the allure of the "IIIF over GraphQL" approach, it just is not very compatible with the way the community works. We can't force every Mirador implementer to host a GraphQL bridge and hosting a central bridge is out of the question for a lot of reasons.
In my opinion, Mirador should work as a purely client-side application that can work with any IIIF v2 or v3 endpoint.
Now, if IIIF-over-GraphQL purely on the client side works and checks all of our boxes, it might be worth a shot. Although it does seem to be a pretty experimental rabbit hole to go down...

@christopher-johnson
Copy link
Contributor

you understand that the "bridge" does not need to be a public service, right? There are many, many node and web applications that depend on a server (and server side rendering). This is not a revolutionary idea, and it is proven technology. I think it is a deal breaker for those who are not thinking about the potential of this new paradigm to synthesize disparate bespoke REST API services, which as far as I can tell is a generally unrealized goal of the IIIF. I do not think it is accurate to say that the IIIF philosophy is keeping it simple. There is a lot of complexity in the model and specifications, and making all of this work in a universal client remains practically a substantial challenge.

@jbaiter
Copy link
Collaborator

jbaiter commented Jan 24, 2019

you understand that the "bridge" does not need to be a public service, right? There are many, many node and web applications that depend on a server (and server side rendering).

But it has to be a service that needs to be configured, deployed and maintained. This completely contradicts the whole "Users should be able to run Mirador by dropping a <script> tag idea.
Also, how would keeping the bridge private (i.e. not accessible from the client's browser) work?

I think it is a deal breaker for those who are not thinking about the potential of this new paradigm to synthesize disparate bespoke REST API services, which as far as I can tell is a generally unrealized goal of the IIIF.

I do realize the potential of GraphQL and I'm absolutely with you on that. I just don't think that this is within scope for the development of Mirador 3, and I thought we all agreed to that during the Kick-Off.

I do not think it is accurate to say that the IIIF philosophy is keeping it simple. There is a lot of complexity in the model and specifications, and making all of this work in a universal client remains practically a substantial challenge.

Absolutely true, and we should strive to solve this substantial challenge while keeping Mirador as simple to use and deploy as possible. I still think that the IIIF philosophy is to keep it simple, even if the reality might not be a simple as many wish for.

@christopher-johnson
Copy link
Contributor

This completely contradicts the whole "Users should be able to run Mirador by dropping a <script> tag idea.

These users have zero possibility to implement a full-featured read-write web annotation platform using this method. Such a platform is one requirement of the Handschriftenportal. So constraining the Mirador 3 project design to the most simple use case does not help us achieve that goal.

I agree that it should be possible for Mirador 3 to work in a zero-configuration legacy mode. But on the other hand, it should equally and seamlessly provide the extensible backend interfaces necessary to support complex distributed systems architecture.

Also, how would keeping the bridge private (i.e. not accessible from the client's browser) work?

Authentication.

@mejackreed
Copy link
Collaborator

There is some great discussion here with a lot of good information about various use cases and strategies.

While I agree that there are some strong architectural considerations on why a GraphQL backend can make our life easier for reading IIIF content, I'm concerned that takes us in a direction that we may not be prepared to handle, as a community of software maintainers and as a community of content providers. I think such a significant change (while already being adopted widely in tech) may be difficult to get initial traction within cultural heritage organizations which constitute the majority of Mirador users. Mirador has chosen the current IIIF as our interoperability platform of choice, and adding a new layer/gateway/bridge/external API to that is out of scope.

screen shot 2019-01-24 at 7 31 58 am

A containing application can and should connect to additional API's. We shouldn't enforce Mirador users to do that though.

implement a full-featured read-write web annotation platform

Yes, Mirador3 can/will function as a viewer within an application that does this. But Mirador 3 cannot take on all of this, and it should handle a simpler scenario (which we are targeting in this first workcycle) while providing an interface for plugins and more complex scenarios.

it should equally and seamlessly provide the extensible backend interfaces necessary to support complex distributed systems architecture

Sure! Though it might be more difficult at first, we need a client that can handle IIIF content first and foremost. I don't think we are closing off this possibility.

I just don't think that this is within scope for the development of Mirador 3, and I thought we all agreed to that during the Kick-Off.

This is also my understanding of agreements from last week. Let's table the GraphQL discussion for now and move the discussion back to be more focused on the original intent of the issue created by @aeschylus ?

For discussions around how Mirador could interact with additional API's beyond IIIF, please create a separate issue. Thanks everyone!

@stephenwf
Copy link

stephenwf commented Jan 31, 2019

With React hooks shipping on monday, I put together some quick examples of using IIIF Redux with it:

Long and short of it is in functional components you can do something like:

function RenderLabel() {
  const { label } = useManifest();

  return <div>{ t(label) }</div>;
}

Then when its a child of (however deep down) of the Manifest context, it will know to load that one.

const App = (
  <Manifest id="...">
    <RenderLabel />
  </Manifest>
);

so in theory, matching the mirador window model

const App = (
  <div>
    <Window id={1}>
      <Manifest url="https://.../manifest1">
        <RenderLabel />
      </Manifest>
    </Window>
    <Window id={2}>
      <Manifest url="https://.../manifest2">
        <RenderLabel />
      </Manifest>
   </Window>
  </div>
);

And all components in that window would have access to each manifest via context.

Nice loose coupling for creating UI that requires bits of IIIF state. It's all still exploratory, but would be keen to get some feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants