From a1838c1ec8ea9a5a4764d693ac332f2472d3f583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maren=20S=C3=BCwer?= Date: Thu, 20 Sep 2018 12:03:49 +0200 Subject: [PATCH] add reducer, selector and actions for getting one changeset --- scm-ui/src/repos/modules/changesets.js | 138 +++++++-- scm-ui/src/repos/modules/changesets.test.js | 307 +++++++++++++++++++- 2 files changed, 420 insertions(+), 25 deletions(-) diff --git a/scm-ui/src/repos/modules/changesets.js b/scm-ui/src/repos/modules/changesets.js index a39bb407c2..dfe1a77f75 100644 --- a/scm-ui/src/repos/modules/changesets.js +++ b/scm-ui/src/repos/modules/changesets.js @@ -16,51 +16,47 @@ export const FETCH_CHANGESETS_PENDING = `${FETCH_CHANGESETS}_${PENDING_SUFFIX}`; export const FETCH_CHANGESETS_SUCCESS = `${FETCH_CHANGESETS}_${SUCCESS_SUFFIX}`; export const FETCH_CHANGESETS_FAILURE = `${FETCH_CHANGESETS}_${FAILURE_SUFFIX}`; -//added for detailed view of changesets +//********added for detailed view of changesets export const FETCH_CHANGESET = "scm/repos/FETCH_CHANGESET"; export const FETCH_CHANGESET_PENDING = `${FETCH_CHANGESET}_${PENDING_SUFFIX}`; export const FETCH_CHANGESET_SUCCESS = `${FETCH_CHANGESET}_${SUCCESS_SUFFIX}`; export const FETCH_CHANGESET_FAILURE = `${FETCH_CHANGESET}_${FAILURE_SUFFIX}`; -// end of detailed view add +//********end of detailed view add // actions const REPO_URL = "repositories"; //TODO: Content type -//added for detailed view of changesets +//********added for detailed view of changesets -function fetchChangesetIfNeeded( +export function fetchChangesetIfNeeded( state: Object, namespace: string, repoName: string, id: string ) { - return function(dispatch) { + return function(dispatch: any) { if (shouldFetchChangeset(state, namespace, repoName, id)) { - dispatch(fetchChangeset(url)); + return dispatch(fetchChangeset(namespace, repoName, id)); } }; } -export function shouldFetchChangeset( - state: Object, +export function fetchChangeset( namespace: string, repoName: string, id: string ) { - // decide if changeset should be fetched here - return true; -} - -function fetchChangeset(namespace: string, repoName: string, id: string) { - return function(dispatch) { + return function(dispatch: any) { dispatch(fetchChangesetPending(namespace, repoName, id)); return apiClient - .get(url) + .get(REPO_URL + `/${namespace}/${repoName}/changesets/${id}`) .then(response => response.json()) - .then(json => dispatch(fetchChangesetSuccess(namespace, repoName, id))) + .then(data => + dispatch(fetchChangesetSuccess(data, namespace, repoName, id)) + ) .catch(err => { dispatch(fetchChangesetFailure(namespace, repoName, id, err)); }); @@ -79,25 +75,26 @@ export function fetchChangesetPending( repoName, id }, - itemId: createItemId(namespace, repoName) + "/" + id + itemId: createItemId(namespace, repoName, id) }; } export function fetchChangesetSuccess( + changeset: any, namespace: string, repoName: string, id: string ): Action { return { type: FETCH_CHANGESET_SUCCESS, - payload: { namespace, repoName, id }, - itemId: createItemId(namespace, repoName) + "/" + id + payload: { changeset, namespace, repoName, id }, + itemId: createItemId(namespace, repoName, id) }; } function fetchChangesetFailure( namespace: string, - name: string, + repoName: string, id: string, error: Error ): Action { @@ -105,15 +102,14 @@ function fetchChangesetFailure( type: FETCH_CHANGESET_FAILURE, payload: { namespace, - name, + repoName, id, error }, - itemId: createItemId(namespace, repoName) + "/" + id + itemId: createItemId(namespace, repoName, id) }; } - -// end of detailed view add +//********end of detailed view add export function fetchChangesetsWithOptions( namespace: string, @@ -234,6 +230,26 @@ function byKeyReducer( action: Action = { type: "UNKNOWN" } ): Object { switch (action.type) { + //********added for detailed view of changesets + case FETCH_CHANGESET_SUCCESS: + const _key = createItemId( + action.payload.namespace, + action.payload.repoName + ); + let _oldChangesets = { [_key]: {} }; + if (state[_key] !== undefined) { + _oldChangesets[_key] = state[_key]; + } + return { + ...state, + [_key]: { + byId: addChangesetToChangesets( + action.payload.changeset, + _oldChangesets[_key].byId + ) + } + }; + //********end of added for detailed view of changesets case FETCH_CHANGESETS_SUCCESS: const key = action.itemId; let oldChangesets = { [key]: {} }; @@ -256,6 +272,18 @@ function listReducer( action: Action = { type: "UNKNOWN" } ): Object { switch (action.type) { + //********added for detailed view of changesets + case FETCH_CHANGESET_SUCCESS: + const changesetId = action.payload.changeset.id; + const stateEntries = state.entries; + stateEntries.push(changesetId); + return { + entries: stateEntries, + entry: { + ...state.entry + } + }; + //********end of added for detailed view of changesets case FETCH_CHANGESETS_SUCCESS: const changesets = action.payload._embedded.changesets; const changesetIds = changesets.map(c => c.id); @@ -291,6 +319,21 @@ function extractChangesetsByIds(data: any, oldChangesetsByIds: any) { return changesetsByIds; } +//********added for detailed view of changesets + +function addChangesetToChangesets(data: any, oldChangesetsByIds: any) { + const changeset = data; + const changesetsByIds = {}; + + changesetsByIds[changeset.id] = changeset; + + for (let id in oldChangesetsByIds) { + changesetsByIds[id] = oldChangesetsByIds[id]; + } + + return changesetsByIds; +} +//********end of added for detailed view of changesets //selectors export function getChangesets( @@ -306,6 +349,53 @@ export function getChangesets( return Object.values(state.changesets.byKey[key].byId); } +//********added for detailed view of changesets +export function getChangeset( + state: Object, + namespace: string, + name: string, + id: string, + branch?: string +) { + const key = createItemId(namespace, name, branch); + const changesets = state.changesets.byKey[key].byId; + if (changesets != null && changesets[id]) { + return changesets[id]; + } + return null; +} + +export function shouldFetchChangeset( + state: Object, + namespace: string, + repoName: string, + id: string +) { + if (getChangeset(state, namespace, repoName, id)) { + return false; + } + return true; +} + +export function isFetchChangesetPending( + state: Object, + namespace: string, + name: string, + id: string +) { + return isPending(state, FETCH_CHANGESET, createItemId(namespace, name, id)); +} + +export function getFetchChangesetFailure( + state: Object, + namespace: string, + name: string, + id: string +) { + return getFailure(state, FETCH_CHANGESET, createItemId(namespace, name, id)); +} +//********end of added for detailed view of changesets + export function isFetchChangesetsPending( state: Object, namespace: string, diff --git a/scm-ui/src/repos/modules/changesets.test.js b/scm-ui/src/repos/modules/changesets.test.js index d46dff8ef7..ae5c9ce6ea 100644 --- a/scm-ui/src/repos/modules/changesets.test.js +++ b/scm-ui/src/repos/modules/changesets.test.js @@ -8,6 +8,10 @@ import { FETCH_CHANGESETS_FAILURE, FETCH_CHANGESETS_PENDING, FETCH_CHANGESETS_SUCCESS, + FETCH_CHANGESET, + FETCH_CHANGESET_FAILURE, + FETCH_CHANGESET_PENDING, + FETCH_CHANGESET_SUCCESS, fetchChangesets, fetchChangesetsByBranchAndPage, fetchChangesetsByNamespaceNameAndBranch, @@ -15,7 +19,14 @@ import { fetchChangesetsSuccess, getChangesets, getFetchChangesetsFailure, - isFetchChangesetsPending + isFetchChangesetsPending, + fetchChangeset, + getChangeset, + fetchChangesetIfNeeded, + shouldFetchChangeset, + isFetchChangesetPending, + getFetchChangesetFailure, + fetchChangesetSuccess } from "./changesets"; import reducer from "./changesets"; @@ -33,6 +44,139 @@ describe("changesets", () => { fetchMock.restore(); }); + //********added for detailed view of changesets + const changesetId = "aba876c0625d90a6aff1494f3d161aaa7008b958"; + + it("should fetch changeset", () => { + fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + changesetId, "{}"); + + const expectedActions = [ + { + type: FETCH_CHANGESET_PENDING, + payload: { + id: changesetId, + namespace: "foo", + repoName: "bar" + }, + itemId: "foo/bar/" + changesetId + }, + { + type: FETCH_CHANGESET_SUCCESS, + payload: { + changeset: {}, + id: changesetId, + namespace: "foo", + repoName: "bar" + }, + itemId: "foo/bar/" + changesetId + } + ]; + + const store = mockStore({}); + return store + .dispatch(fetchChangeset("foo", "bar", changesetId)) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it("should fail fetching changeset on error", () => { + fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + changesetId, 500); + + const expectedActions = [ + { + type: FETCH_CHANGESET_PENDING, + payload: { + id: changesetId, + namespace: "foo", + repoName: "bar" + }, + itemId: "foo/bar/" + changesetId + } + ]; + + const store = mockStore({}); + return store + .dispatch(fetchChangeset("foo", "bar", changesetId)) + .then(() => { + expect(store.getActions()[0]).toEqual(expectedActions[0]); + expect(store.getActions()[1].type).toEqual(FETCH_CHANGESET_FAILURE); + expect(store.getActions()[1].payload).toBeDefined(); + }); + }); + + it("should fetch changeset if needed", () => { + fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + "id3", "{}"); + + const state = { + changesets: { + byKey: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + } + }; + + const expectedActions = [ + { + type: FETCH_CHANGESET_PENDING, + payload: { + id: "id3", + namespace: "foo", + repoName: "bar" + }, + itemId: "foo/bar/" + "id3" + }, + { + type: FETCH_CHANGESET_SUCCESS, + payload: { + changeset: {}, + id: "id3", + namespace: "foo", + repoName: "bar" + }, + itemId: "foo/bar/" + "id3" + } + ]; + + const store = mockStore({}); + return store + .dispatch(fetchChangesetIfNeeded(state, "foo", "bar", "id3")) + .then(() => { + expect(store.getActions()).toEqual(expectedActions); + }); + }); + + it("should not fetch changeset if not needed", () => { + fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + "id1", 500); + + const state = { + changesets: { + byKey: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + } + }; + + const expectedActions = []; + + const store = mockStore({}); + return expect( + store.dispatch(fetchChangesetIfNeeded(state, "foo", "bar", "id1")) + ).toEqual(undefined); + }); + + //********end of added for detailed view of changesets + it("should fetch changesets for default branch", () => { fetchMock.getOnce(DEFAULT_BRANCH_URL, "{}"); @@ -248,11 +392,172 @@ describe("changesets", () => { expect(newState.byKey["foo/bar"].byId["changeset2"]).toBeDefined(); expect(newState.byKey["foo/bar"].byId["changeset1"]).toBeDefined(); }); + + //********added for detailed view of changesets + const responseBodySingleChangeset = { + id: "id3", + author: { + mail: "z@phod.com", + name: "zaphod" + }, + date: "2018-09-13T08:46:22Z", + description: "added testChangeset", + _links: {}, + _embedded: { + tags: [], + branches: [] + } + }; + + it("should add changeset to state", () => { + const newState = reducer( + { + byKey: { + "foo/bar": { + byId: { + ["id2"]: { + id: "id2", + author: { mail: "mail@author.com", name: "author" } + } + } + } + }, + list: { + entry: { + page: 1, + pageTotal: 10, + _links: {} + }, + entries: ["id2"] + } + }, + fetchChangesetSuccess(responseBodySingleChangeset, "foo", "bar", "id3") + ); + expect(newState).toBeDefined(); + expect(newState.byKey["foo/bar"].byId["id3"].description).toEqual( + "added testChangeset" + ); + expect(newState.byKey["foo/bar"].byId["id3"].author.mail).toEqual( + "z@phod.com" + ); + expect(newState.byKey["foo/bar"].byId["id2"]).toBeDefined(); + expect(newState.byKey["foo/bar"].byId["id3"]).toBeDefined(); + expect(newState.list).toEqual({ + entry: { + page: 1, + pageTotal: 10, + _links: {} + }, + entries: ["id2", "id3"] + }); + }); + //********end of added for detailed view of changesets }); describe("changeset selectors", () => { const error = new Error("Something went wrong"); + //********added for detailed view of changesets + + it("should return changeset", () => { + const state = { + changesets: { + byKey: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + } + }; + const result = getChangeset(state, "foo", "bar", "id1"); + expect(result).toEqual({ id: "id1" }); + }); + + it("should return null if changeset does not exist", () => { + const state = { + changesets: { + byKey: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + } + }; + const result = getChangeset(state, "foo", "bar", "id3"); + expect(result).toEqual(null); + }); + + it("should return true if changeset does not exist", () => { + const state = { + changesets: { + byKey: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + } + }; + const result = shouldFetchChangeset(state, "foo", "bar", "id3"); + expect(result).toEqual(true); + }); + + it("should return false if changeset exists", () => { + const state = { + changesets: { + byKey: { + "foo/bar": { + byId: { + id1: { id: "id1" }, + id2: { id: "id2" } + } + } + } + } + }; + const result = shouldFetchChangeset(state, "foo", "bar", "id2"); + expect(result).toEqual(false); + }); + + it("should return true, when fetching changeset is pending", () => { + const state = { + pending: { + [FETCH_CHANGESET + "/foo/bar/id1"]: true + } + }; + + expect(isFetchChangesetPending(state, "foo", "bar", "id1")).toBeTruthy(); + }); + + it("should return false, when fetching changeset is not pending", () => { + expect(isFetchChangesetPending({}, "foo", "bar", "id1")).toEqual(false); + }); + + it("should return error if fetching changeset failed", () => { + const state = { + failure: { + [FETCH_CHANGESET + "/foo/bar/id1"]: error + } + }; + + expect(getFetchChangesetFailure(state, "foo", "bar", "id1")).toEqual( + error + ); + }); + + it("should return false if fetching changeset did not fail", () => { + expect(getFetchChangesetFailure({}, "foo", "bar", "id1")).toBeUndefined(); + }); + //********end of added for detailed view of changesets + it("should get all changesets for a given namespace and name", () => { const state = { changesets: {