From 1314685c5a19d3083e74acfc6a97e1bde681954a Mon Sep 17 00:00:00 2001 From: "imranasghar96@hotmail.com" Date: Mon, 2 Nov 2020 14:46:05 -0500 Subject: [PATCH 1/4] Get multi-sequences to work for v3 ranges/seqs - Update sequences and canvases selectors to get multi-sequences to work for v3 top-level ranges with behavior sequence, check if full canvases exist in each sequence - Add integration test for v3 multi sequences --- .../fixtures/version-3/multipleSequences.json | 59 +++++++++++++++++++ .../mirador/sequence_switching_v3.test.js | 34 +++++++++++ src/state/selectors/canvases.js | 29 +++++++-- src/state/selectors/sequences.js | 33 +++++++++-- 4 files changed, 145 insertions(+), 10 deletions(-) create mode 100644 __tests__/fixtures/version-3/multipleSequences.json create mode 100644 __tests__/integration/mirador/sequence_switching_v3.test.js diff --git a/__tests__/fixtures/version-3/multipleSequences.json b/__tests__/fixtures/version-3/multipleSequences.json new file mode 100644 index 0000000000..4f84d0bc00 --- /dev/null +++ b/__tests__/fixtures/version-3/multipleSequences.json @@ -0,0 +1,59 @@ +{ + "@context": [ + "http://iiif.io/api/presentation/3/context.json" + ], + "id": "http://foo.test/1/manifest", + "type": "Manifest", + "label": { + "none": ["Version 3 manifest for multiple ranges (sequences behavior) related tests"] + }, + "items": [ + { + "id": "http://foo.test/1/canvas/c1", + "type": "Canvas", + "label":{"none":["Test Canvas 1"]} + }, + { + "id": "http://foo.test/1/canvas/c2", + "type": "Canvas", + "label":{"none":["Test Canvas 2"]} + }, + { + "id": "http://foo.test/1/canvas/c3", + "type": "Canvas", + "label":{"none":["Test Canvas 3"]} + } + ], + "structures": [ + { + "id": "http://foo.test/1/range/root", + "type": "Range", + "behavior": "sequence", + "items": [ + { + "id": "http://foo.test/1/canvas/c1", + "type": "Canvas", + "label":{"none":["Test Canvas 1"]} + } + ] + }, + { + "id": "http://foo.test/1/range/second", + "type": "Range", + "behavior": "sequence", + "items": [ + { + "id": "http://foo.test/1/canvas/c2", + "type": "Canvas", + "label":{"none":["Test Canvas 2"]} + }, + { + "id": "http://foo.test/1/canvas/c3", + "type": "Canvas", + "label":{"none":["Test Canvas 3"]} + } + ] + } + ] + } + \ No newline at end of file diff --git a/__tests__/integration/mirador/sequence_switching_v3.test.js b/__tests__/integration/mirador/sequence_switching_v3.test.js new file mode 100644 index 0000000000..a9f64680b1 --- /dev/null +++ b/__tests__/integration/mirador/sequence_switching_v3.test.js @@ -0,0 +1,34 @@ +/* global miradorInstance */ + +describe('Window Sidebar Sequence Dropdown v3', () => { + beforeAll(async () => { + await page.goto('http://127.0.0.1:4488/__tests__/integration/mirador/blank.html'); + + await expect(page).toClick('#addBtn'); + await expect(page).toClick('.mirador-add-resource-button'); + await expect(page).toFill('#manifestURL', 'http://localhost:4488/__tests__/fixtures/version-3/multipleSequences.json'); + await expect(page).toClick('#fetchBtn'); + + await expect(page).toMatchElement('[data-manifestid="http://localhost:4488/__tests__/fixtures/version-3/multipleSequences.json"] button'); + await expect(page).toClick('[data-manifestid="http://localhost:4488/__tests__/fixtures/version-3/multipleSequences.json"] button'); + }); + + it('allows the user to switch the v3 ranges (behavior sequences)', async () => { + const windows = await page.evaluate(() => ( + miradorInstance.store.getState().windows + )); + + const windowId = Object.values(windows) + .find(window => window.manifestId === 'http://localhost:4488/__tests__/fixtures/version-3/multipleSequences.json') + .id; + + await expect(page).toMatchElement(`#${windowId} button[aria-label="Toggle sidebar"]`); + await expect(page).toClick(`#${windowId} button[aria-label="Toggle sidebar"]`); + await expect(page).toMatchElement(`#${windowId} button[aria-label="Index"]`); + await expect(page).toClick(`#${windowId} button[aria-label="Index"]`); + await expect(page).toClick('#mui-component-select-sequenceId'); + await expect(page).toMatchElement('[data-value="http://foo.test/1/range/second"]'); + await expect(page).toClick('[data-value="http://foo.test/1/range/second"]'); + await expect(page).toMatchElement('p', { text: 'Test Canvas 2' }); + }); +}); diff --git a/src/state/selectors/canvases.js b/src/state/selectors/canvases.js index 8078bf823c..2a8f88c7fb 100644 --- a/src/state/selectors/canvases.js +++ b/src/state/selectors/canvases.js @@ -12,7 +12,8 @@ export const selectInfoResponses = state => miradorSlice(state).infoResponses; export const getCanvases = createSelector( [getSequence], - sequence => (sequence && sequence.getCanvases()) || [], + sequence => (sequence && ((sequence.getCanvases && sequence.getCanvases()) || sequence.items)) + || [], ); /** @@ -29,9 +30,16 @@ export const getCanvas = createSelector( (state, { canvasId }) => canvasId, ], (sequence, canvasId) => { + let canvas; if (!sequence || !canvasId) return undefined; - return sequence.getCanvasById(canvasId); + if (typeof sequence.getCanvasById == 'function') { + canvas = sequence.getCanvasById(canvasId); + } else if (sequence.items) { + canvas = sequence.items.filter(c => c.id === canvasId) || []; + } + + return canvas; }, ); @@ -41,11 +49,24 @@ export const getCurrentCanvas = createSelector( getWindow, ], (sequence, window) => { + let canvas; if (!sequence || !window) return undefined; - if (!window.canvasId) return sequence.getCanvasByIndex(0); + if (!window.canvasId && (typeof sequence.getCanvasByIndex == 'function')) { + canvas = sequence.getCanvasByIndex(0); + } else if (!window.canvasId) { + const { items } = sequence; + const [firstCanvas] = items; + canvas = firstCanvas; + } + + if (typeof sequence.getCanvasById == 'function') { + canvas = sequence.getCanvasById(window.canvasId); + } else if (sequence.items) { + canvas = sequence.items.filter(c => c.id === window.canvasId) || []; + } - return sequence.getCanvasById(window.canvasId); + return canvas; }, ); diff --git a/src/state/selectors/sequences.js b/src/state/selectors/sequences.js index 6e90dc08b8..f8b538bc4e 100644 --- a/src/state/selectors/sequences.js +++ b/src/state/selectors/sequences.js @@ -1,5 +1,6 @@ import { createSelector } from 'reselect'; import { TreeNode } from 'manifesto.js/dist-esmodule/TreeNode'; +import { v3 } from 'uuid'; import { getManifestoInstance, } from './manifests'; @@ -16,6 +17,20 @@ export const getSequences = createSelector( if (v2TopRanges.length === 0 && topRangesOrRoot.length === 1) { v3RangeSequences = topRangesOrRoot[0].getRanges().filter(r => r.getBehavior() === 'sequence'); + + if (v3RangeSequences.length > 0 && manifest.items && manifest.items.length > 0 + && manifest.items[0].items && manifest.items[0].items.length > 0) { + const canvases = manifest.items[0].items; + + v3RangeSequences.map((sequence) => { + const updatedSequence = sequence; + updatedSequence.items = sequence.canvases.map(canvasId => { + const fullCanvas = canvases.find(c => c.id === canvasId); + return fullCanvas; + }); + return updatedSequence; + }); + } } const sequences = [].concat( @@ -37,10 +52,8 @@ export const getSequence = createSelector( ], (sequences, window, sequenceId) => { if (!sequences) return null; - if (sequenceId || (window && window.sequenceId)) { const currentSequence = sequences.find(s => s.id === (sequenceId || window.sequenceId)); - if (currentSequence) return currentSequence; } @@ -58,10 +71,18 @@ export const getCanvasIndex = createSelector( getWindow, getSequence, ], - (window, sequence) => ( - (sequence && window && window.canvasId - && sequence.getCanvasById(window.canvasId)) - || {}).index || 0, + (window, sequence) => { + let canvas; + + if (sequence && window && window.canvasId + && typeof sequence.getCanvasById == 'function') { + canvas = sequence.getCanvasById(window.canvasId); + } else { + canvas = {}; + } + + return canvas.index || 0; + }, ); /** From c97d5dab7f304a4fbc6b99778abc02f45a5e068e Mon Sep 17 00:00:00 2001 From: "imranasghar96@hotmail.com" Date: Mon, 9 Nov 2020 22:12:49 -0500 Subject: [PATCH 2/4] Add multi-seq select option to display.. ... all items including ToC for v3, other changes - Display an option in multi seq select bar that displays all the canvases in v3 sequence along with ToC - Constrain the size of multi seqs select bar - Change sequences test to expect uuid instead of undefined id for first v3 sequence - Add checkes in getSequences selector before setting id for first v3 sequence which has undefined id initially --- __tests__/src/selectors/sequences.test.js | 4 +++- src/components/WindowSideBarCanvasPanel.js | 5 ++--- src/containers/WindowSideBarCanvasPanel.js | 9 ++++++++ src/state/sagas/annotations.js | 4 +++- src/state/selectors/sequences.js | 26 +++++++++++++++------- 5 files changed, 35 insertions(+), 13 deletions(-) diff --git a/__tests__/src/selectors/sequences.test.js b/__tests__/src/selectors/sequences.test.js index 240fa6004a..8b94e6d1f4 100644 --- a/__tests__/src/selectors/sequences.test.js +++ b/__tests__/src/selectors/sequences.test.js @@ -13,6 +13,8 @@ import { getSequenceBehaviors, } from '../../../src/state/selectors/sequences'; +jest.mock('uuid', () => ({ v4: () => '00000000-0000-0000-0000-000000000000' })); + describe('getSequences', () => { describe('with a v2 manifest', () => { const state = { manifests: { x: { json: manifestFixtureGau } } }; @@ -49,7 +51,7 @@ describe('getSequences', () => { const state = { manifests: { x: { json: manifest } } }; const sequences = getSequences(state, { manifestId: 'x' }); expect(sequences.length).toEqual(3); - expect(sequences.map(s => s.id)).toEqual([undefined, 'a', 'b']); + expect(sequences.map(s => s.id)).toEqual(['00000000-0000-0000-0000-000000000000', 'a', 'b']); }); }); diff --git a/src/components/WindowSideBarCanvasPanel.js b/src/components/WindowSideBarCanvasPanel.js index abd76e08f4..69d1513065 100644 --- a/src/components/WindowSideBarCanvasPanel.js +++ b/src/components/WindowSideBarCanvasPanel.js @@ -88,7 +88,6 @@ export class WindowSideBarCanvasPanel extends Component { /> ); } - return ( { sequences && sequences.length > 1 && ( - +