Skip to content

Commit

Permalink
Save search parameters with auto-updating lists. (#39)
Browse files Browse the repository at this point in the history
* Save and load search facets in auto updating lists.

* Add tests.

* Add a proper type declaration.

* Fix a test.
  • Loading branch information
ray-lee authored Sep 1, 2022
1 parent f41a443 commit b68a32b
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## Changelog

### v0.2.1

#### Fixed

- The selected media type and sort order are now correctly saved with auto updating lists.

### v0.2.0

#### Updated
Expand Down
145 changes: 143 additions & 2 deletions src/reducers/__tests__/customListEditor-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ describe("custom list editor reducer", () => {
auto_update_query:
'{"query":{"and":[{"and":[{"or":[{"key":"genre","value":"Horror"},{"key":"genre","value":"Fantasy"}]},{"key":"language","value":"eng"},{"key":"classification","value":"mystery"}]},{"not":[{"or":[{"key":"author","op":"contains","value":"bracken"},{"key":"title","value":"wicked appetite"}]}]}]}}',
},
{
collections: [],
id: 42,
name: "Another Auto Updating List",
auto_update: true,
auto_update_facets: '{"media":"Audio","order":"title"}',
},
],
};

Expand Down Expand Up @@ -352,6 +359,21 @@ describe("custom list editor reducer", () => {
});
});

it("updates the search params when there are saved search facets", () => {
const state = {
...initialState,
id: 42,
};

const nextState = reducer(state, {
type: `${ActionCreator.CUSTOM_LISTS}_${ActionCreator.LOAD}`,
data: listData,
});

expect(nextState.searchParams.current.entryPoint).to.equal("Audio");
expect(nextState.searchParams.current.sort).to.equal("title");
});

context("when auto update is enabled", () => {
it("defaults the autoUpdate property to true for a new list", () => {
const state = {
Expand Down Expand Up @@ -2369,6 +2391,125 @@ describe("custom list editor reducer", () => {
'{"query":{"key":"title","value":"Little Women"}}'
);
});

it("should include auto update facets if the list is auto updating", () => {
const state = {
...initialState,
id: 123,
properties: {
...initialState.properties,
current: {
...initialState.properties.current,
name: "My New List",
autoUpdate: true,
},
},
searchParams: {
...initialState.searchParams,
current: {
...initialState.searchParams.current,
entryPoint: "Audio",
sort: "title",
advanced: {
...initialState.searchParams.current.advanced,
include: {
...initialState.searchParams.current.advanced.include,
query: {
id: "0",
key: "title",
op: "eq",
value: "Little Women",
},
},
},
},
},
};

const formData = getCustomListEditorFormData(state);

expect(formData.get("auto_update_facets")).to.equal(
'{"media":"Audio","order":"title"}'
);
});

it('should not include media in auto update facets if entryPoint is "All"', () => {
const state = {
...initialState,
id: 123,
properties: {
...initialState.properties,
current: {
...initialState.properties.current,
name: "My New List",
autoUpdate: true,
},
},
searchParams: {
...initialState.searchParams,
current: {
...initialState.searchParams.current,
entryPoint: "All",
sort: "title",
advanced: {
...initialState.searchParams.current.advanced,
include: {
...initialState.searchParams.current.advanced.include,
query: {
id: "0",
key: "title",
op: "eq",
value: "Little Women",
},
},
},
},
},
};

const formData = getCustomListEditorFormData(state);

expect(formData.get("auto_update_facets")).to.equal('{"order":"title"}');
});

it("should not include order in auto update facets if sort is null", () => {
const state = {
...initialState,
id: 123,
properties: {
...initialState.properties,
current: {
...initialState.properties.current,
name: "My New List",
autoUpdate: true,
},
},
searchParams: {
...initialState.searchParams,
current: {
...initialState.searchParams.current,
entryPoint: "Book",
sort: null,
advanced: {
...initialState.searchParams.current.advanced,
include: {
...initialState.searchParams.current.advanced.include,
query: {
id: "0",
key: "title",
op: "eq",
value: "Little Women",
},
},
},
},
},
};

const formData = getCustomListEditorFormData(state);

expect(formData.get("auto_update_facets")).to.equal('{"media":"Book"}');
});
});

context("getCustomListEditorSearchUrl", () => {
Expand Down Expand Up @@ -2400,11 +2541,11 @@ describe("custom list editor reducer", () => {
const url = getCustomListEditorSearchUrl(state, library);

expect(url).to.equal(
"/lib/search?entrypoint=Book&order=title&q=foo%20bar%20baz"
"/lib/search?media=Book&order=title&q=foo%20bar%20baz"
);
});

it('should omit the entrypoint param if it is "All"', () => {
it('should omit the media param if entryPoint is "All"', () => {
const state = {
...initialState,
searchParams: {
Expand Down
60 changes: 58 additions & 2 deletions src/reducers/customListEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,31 @@ export const buildAdvSearchQuery = (
return null;
};

/**
* Build a serialized JSON string representing the search facets (media type, sort order) in some
* given search parameters, suitable for sending to the CM when saving an auto updating list.
*
* @param searchParams The search parameters
* @returns The JSON string representing the search facets
*/

export const buildSearchFacetString = (
searchParams: CustomListEditorSearchParams
): string => {
const { entryPoint, sort } = searchParams;
const facets: Record<string, string> = {};

if (entryPoint !== "All") {
facets.media = entryPoint;
}

if (sort) {
facets.order = sort;
}

return JSON.stringify(facets);
};

/**
* Build a serialized JSON string representing the advanced search query in some given search
* parameters, suitable for sending to the CM to execute the search.
Expand All @@ -82,7 +107,7 @@ export const buildAdvSearchQuery = (
* @param indentSpaces The number of spaces to use to indent the JSON. If > 0, the JSON is
* pretty-printed on multiple lines. If 0, a single line of JSON is returned.
* @param encode If true, URL-encode the JSON.
* @returns The JSON string representingg the advanced search query
* @returns The JSON string representing the advanced search query
*/
export const buildAdvSearchQueryString = (
searchParams: CustomListEditorSearchParams,
Expand Down Expand Up @@ -149,6 +174,11 @@ export const getCustomListEditorFormData = (
"auto_update_query",
buildAdvSearchQueryString(searchParams.current, 0, false)
);

data.append(
"auto_update_facets",
buildSearchFacetString(searchParams.current)
);
} else {
const { baseline, current, removed } = entries;

Expand Down Expand Up @@ -185,7 +215,7 @@ export const buildSearchUrl = (
const queryParams = [];

if (entryPoint !== "All") {
queryParams.push(`entrypoint=${encodeURIComponent(entryPoint)}`);
queryParams.push(`media=${encodeURIComponent(entryPoint)}`);
}

if (sort) {
Expand Down Expand Up @@ -324,6 +354,20 @@ export const parseAdvancedSearchQuery = (
return [query, null];
};

/**
* Parse JSON-serialized search facets.
*
* @param json The serialized search facets
* @returns An object containg facet names and values, which may be empty.
*/
const parseSearchFacets = (json: string): Record<string, string> => {
if (!json) {
return {};
}

return JSON.parse(json) || {};
};

/**
* Information about the entries in a list that is being edited.
*/
Expand Down Expand Up @@ -763,6 +807,18 @@ const initialStateForList = (
draftState.searchParams.baseline.advanced.exclude.query = excludeQuery;
draftState.searchParams.current.advanced.include.query = includeQuery;
draftState.searchParams.current.advanced.exclude.query = excludeQuery;

const { media, order } = parseSearchFacets(customList.auto_update_facets);

if (media) {
draftState.searchParams.baseline.entryPoint = media;
draftState.searchParams.current.entryPoint = media;
}

if (order) {
draftState.searchParams.baseline.sort = order;
draftState.searchParams.current.sort = order;
}
}

draftState.error = error;
Expand Down

0 comments on commit b68a32b

Please sign in to comment.