)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":20970,"name":"Honza Pokorny","email":"honza@redhat.com","username":"hpokorny"},"change_message_id":"c3ad8d36e1972627bcdcbd28cded89ac8ad26fd3","unresolved":false,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add deployment status tracking infrastructure"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"This change is a first step of adding support for config-download, it introduces actions, reducers, selectors and immutable records to track deployment status"},{"line_number":10,"context_line":""},{"line_number":11,"context_line":"Change-Id: I748f5151949327ace7f7d824cc5c29a00df0437a"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"bf659307_ff990179","line":9,"range":{"start_line":9,"start_character":0,"end_line":9,"end_character":11},"updated":"2018-04-05 13:37:53.000000000","message":"wrap to 72 chars","commit_id":"a54416610a2d3fd881f5b03f3bb7f617edce4896"},{"author":{"_account_id":7509,"name":"Jiri Tomasek","email":"jtomasek@redhat.com","username":"jtomasek"},"change_message_id":"a4e7eb5a6caf090743c13bbbe60cfbf81d3b35b7","unresolved":false,"context_lines":[{"line_number":6,"context_line":""},{"line_number":7,"context_line":"Add deployment status tracking infrastructure"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"This change is a first step of adding support for config-download, it introduces actions, reducers, selectors and immutable records to track deployment status"},{"line_number":10,"context_line":""},{"line_number":11,"context_line":"Change-Id: I748f5151949327ace7f7d824cc5c29a00df0437a"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":4,"id":"bf659307_f165a346","line":9,"range":{"start_line":9,"start_character":0,"end_line":9,"end_character":11},"in_reply_to":"bf659307_ff990179","updated":"2018-04-06 09:14:12.000000000","message":"Done","commit_id":"a54416610a2d3fd881f5b03f3bb7f617edce4896"}],"src/js/actions/DeploymentActions.js":[{"author":{"_account_id":20970,"name":"Honza Pokorny","email":"honza@redhat.com","username":"hpokorny"},"change_message_id":"5255ae6b49ee4c503aff4fefa9e930e2bafc7549","unresolved":false,"context_lines":[{"line_number":63,"context_line":"    .catch(error \u003d\u003e {"},{"line_number":64,"context_line":"      // If object is not found, deployment status is undefined"},{"line_number":65,"context_line":"      if (error.name \u003d\u003d\u003d \u0027SwiftApiError\u0027 \u0026\u0026 error.response.status \u003d\u003d\u003d 404) {"},{"line_number":66,"context_line":"        dispatch(getDeploymentStatusSuccess(planName));"},{"line_number":67,"context_line":"      } else {"},{"line_number":68,"context_line":"        dispatch("},{"line_number":69,"context_line":"          handleErrors("}],"source_content_type":"text/javascript","patch_set":9,"id":"9f6a8fd7_fd11b605","line":66,"range":{"start_line":66,"start_character":8,"end_line":66,"end_character":55},"updated":"2018-05-02 13:38:16.000000000","message":"How can this be a success when the data can\u0027t be found?","commit_id":"d899b82b08c92c7758bd10e2ace4af3ab8a710c5"},{"author":{"_account_id":7509,"name":"Jiri Tomasek","email":"jtomasek@redhat.com","username":"jtomasek"},"change_message_id":"b04baab5c09f9559fa701e4d1f9ea67b7043b8d3","unresolved":false,"context_lines":[{"line_number":61,"context_line":"      dispatch(getDeploymentStatusSuccess(planName, { status, message, type }));"},{"line_number":62,"context_line":"    })"},{"line_number":63,"context_line":"    .catch(error \u003d\u003e {"},{"line_number":64,"context_line":"      if (error.name \u003d\u003d\u003d \u0027SwiftApiError\u0027 \u0026\u0026 error.response.status \u003d\u003d\u003d 404) {"},{"line_number":65,"context_line":"        dispatch(getDeploymentStatusSuccess(planName));"},{"line_number":66,"context_line":"      } else {"},{"line_number":67,"context_line":"        dispatch("},{"line_number":68,"context_line":"          handleErrors("},{"line_number":69,"context_line":"            error,"}],"source_content_type":"text/javascript","patch_set":13,"id":"5f7c97a3_0cc44b90","line":66,"range":{"start_line":64,"start_character":6,"end_line":66,"end_character":14},"updated":"2018-05-11 14:05:46.000000000","message":"We can remove this in subsequent patch after create_plan workflow updates deployment status.","commit_id":"e5cda08547edbaebfd846ff57d17e261cea731f1"}],"src/js/constants/DeploymentConstants.js":[{"author":{"_account_id":20970,"name":"Honza Pokorny","email":"honza@redhat.com","username":"hpokorny"},"change_message_id":"c3ad8d36e1972627bcdcbd28cded89ac8ad26fd3","unresolved":false,"context_lines":[{"line_number":33,"context_line":"export const deploymentStatusMessages \u003d defineMessages({"},{"line_number":34,"context_line":"  UNDEPLOYED: {"},{"line_number":35,"context_line":"    id: \u0027DeploymentStatus.undeployed\u0027,"},{"line_number":36,"context_line":"    defaultMessage: \u0027Deployment is not deployed yet\u0027"},{"line_number":37,"context_line":"  },"},{"line_number":38,"context_line":"  DEPLOYED: {"},{"line_number":39,"context_line":"    id: \u0027DeploymentStatus.deployed\u0027,"}],"source_content_type":"text/javascript","patch_set":4,"id":"bf659307_5fb02dde","line":36,"range":{"start_line":36,"start_character":21,"end_line":36,"end_character":51},"updated":"2018-04-05 13:37:53.000000000","message":"This is awkward.  Maybe \"Deployment not started\"?","commit_id":"a54416610a2d3fd881f5b03f3bb7f617edce4896"},{"author":{"_account_id":7509,"name":"Jiri Tomasek","email":"jtomasek@redhat.com","username":"jtomasek"},"change_message_id":"a4e7eb5a6caf090743c13bbbe60cfbf81d3b35b7","unresolved":false,"context_lines":[{"line_number":33,"context_line":"export const deploymentStatusMessages \u003d defineMessages({"},{"line_number":34,"context_line":"  UNDEPLOYED: {"},{"line_number":35,"context_line":"    id: \u0027DeploymentStatus.undeployed\u0027,"},{"line_number":36,"context_line":"    defaultMessage: \u0027Deployment is not deployed yet\u0027"},{"line_number":37,"context_line":"  },"},{"line_number":38,"context_line":"  DEPLOYED: {"},{"line_number":39,"context_line":"    id: \u0027DeploymentStatus.deployed\u0027,"}],"source_content_type":"text/javascript","patch_set":4,"id":"bf659307_71519362","line":36,"range":{"start_line":36,"start_character":21,"end_line":36,"end_character":51},"in_reply_to":"bf659307_5fb02dde","updated":"2018-04-06 09:14:12.000000000","message":"Done","commit_id":"a54416610a2d3fd881f5b03f3bb7f617edce4896"},{"author":{"_account_id":10112,"name":"Jason E. Rist","email":"jrist@redhat.com","username":"jrist"},"change_message_id":"9de4d7c3f13ade588ef1ea626b31a46d9c4da2fd","unresolved":false,"context_lines":[{"line_number":48,"context_line":"  },"},{"line_number":49,"context_line":"  DEPLOYING: {"},{"line_number":50,"context_line":"    id: \u0027DeploymentStatus.deploying\u0027,"},{"line_number":51,"context_line":"    defaultMessage: \u0027Deployment of {planName} plan is currently in progress.\u0027"},{"line_number":52,"context_line":"  },"},{"line_number":53,"context_line":"  UNDEPLOYING: {"},{"line_number":54,"context_line":"    id: \u0027DeploymentStatus.undeploying\u0027,"}],"source_content_type":"text/javascript","patch_set":8,"id":"9f6a8fd7_253a1534","line":51,"updated":"2018-04-26 22:02:56.000000000","message":"Some periods here and not in other sentences. What\u0027s the rubric?","commit_id":"e43b1498183fe34fde6a5914d3062c06d13eb95a"},{"author":{"_account_id":7509,"name":"Jiri Tomasek","email":"jtomasek@redhat.com","username":"jtomasek"},"change_message_id":"2980ef0138c6f68cc7358d32d1cd843dede23659","unresolved":false,"context_lines":[{"line_number":48,"context_line":"  },"},{"line_number":49,"context_line":"  DEPLOYING: {"},{"line_number":50,"context_line":"    id: \u0027DeploymentStatus.deploying\u0027,"},{"line_number":51,"context_line":"    defaultMessage: \u0027Deployment of {planName} plan is currently in progress.\u0027"},{"line_number":52,"context_line":"  },"},{"line_number":53,"context_line":"  UNDEPLOYING: {"},{"line_number":54,"context_line":"    id: \u0027DeploymentStatus.undeploying\u0027,"}],"source_content_type":"text/javascript","patch_set":8,"id":"9f6a8fd7_dea99f24","line":51,"in_reply_to":"9f6a8fd7_253a1534","updated":"2018-04-27 08:21:06.000000000","message":"Done","commit_id":"e43b1498183fe34fde6a5914d3062c06d13eb95a"}],"src/js/immutableRecords/deploymentStatus.js":[{"author":{"_account_id":20970,"name":"Honza Pokorny","email":"honza@redhat.com","username":"hpokorny"},"change_message_id":"5255ae6b49ee4c503aff4fefa9e930e2bafc7549","unresolved":false,"context_lines":[{"line_number":25,"context_line":"  type: undefined"},{"line_number":26,"context_line":"});"},{"line_number":27,"context_line":""},{"line_number":28,"context_line":"export const DeploymentStatusUI \u003d Record({"},{"line_number":29,"context_line":"  error: undefined,"},{"line_number":30,"context_line":"  isLoaded: false,"},{"line_number":31,"context_line":"  isFetching: false"}],"source_content_type":"text/javascript","patch_set":9,"id":"9f6a8fd7_dddcf247","line":28,"updated":"2018-05-02 13:38:16.000000000","message":"I don\u0027t like the *UI naming here.  Everything we do is UI.","commit_id":"d899b82b08c92c7758bd10e2ace4af3ab8a710c5"},{"author":{"_account_id":20970,"name":"Honza Pokorny","email":"honza@redhat.com","username":"hpokorny"},"change_message_id":"151dbe10ab62e9ffa9a50045a32e0d19e4731b08","unresolved":false,"context_lines":[{"line_number":25,"context_line":"  type: undefined"},{"line_number":26,"context_line":"});"},{"line_number":27,"context_line":""},{"line_number":28,"context_line":"export const DeploymentStatusUI \u003d Record({"},{"line_number":29,"context_line":"  error: undefined,"},{"line_number":30,"context_line":"  isLoaded: false,"},{"line_number":31,"context_line":"  isFetching: false"}],"source_content_type":"text/javascript","patch_set":14,"id":"5f7c97a3_82280097","line":28,"updated":"2018-05-14 16:53:25.000000000","message":"Based on our naming convention, this should be called DeploymentStatusState.  And it should have a \"status\" or \"deploymentStatus\" entry which will carry a DeploymentStatus instance.","commit_id":"a50d4b71dc14f7213d1659fe993b729a4c7607df"},{"author":{"_account_id":7509,"name":"Jiri Tomasek","email":"jtomasek@redhat.com","username":"jtomasek"},"change_message_id":"c99533620aab6ac62359cdeb0f059ca22e233b06","unresolved":false,"context_lines":[{"line_number":25,"context_line":"  type: undefined"},{"line_number":26,"context_line":"});"},{"line_number":27,"context_line":""},{"line_number":28,"context_line":"export const DeploymentStatusUI \u003d Record({"},{"line_number":29,"context_line":"  error: undefined,"},{"line_number":30,"context_line":"  isLoaded: false,"},{"line_number":31,"context_line":"  isFetching: false"}],"source_content_type":"text/javascript","patch_set":14,"id":"5f7c97a3_2ade95d9","line":28,"in_reply_to":"5f7c97a3_82280097","updated":"2018-05-15 11:51:55.000000000","message":"The deployment states are tracked by plan name, in our app, we use \u003csomething\u003eStatus Record to define default state used by certain reducer. In case of deployment status, this default is an empty Map(). DeploymentStatus Record is a single instance of deployment status. Yes it could still be named DeploymentStatusState as a wrapping Record which includes nested deploymentStatus key which would hold DeploymentStatus instance.\nDoing this makes the state and reducers more complicated than it could be.\n\nWhat I did is, instead of having single reducer handling and managing complicated, nested chunk of app state, I created 2 separate chunks of app state managed by 2 separate reducers which are then combined and added to appReducer.\n\nInstead of\n\n{\n  \u0027overcloud\u0027: {\n    error: undefined,\n    isLoaded: false,\n    isFetching: false,\n    deploymentStatus: {\n      configDownloadMessages: List(),\n      message: undefined,\n      status: \u0027UNDEPLOYED\u0027,\n      type: undefined\n    },\n  \u0027othercloud\u0027: {...}\n}\n\nI did\n\n{\n  \u0027overcloud\u0027: {\n    error: undefined,\n    isLoaded: false,\n    isFetching: false \n  },\n  \u0027othercloud\u0027: {\n    error: undefined,\n    isLoaded: false,\n    isFetching: false \n  }\n}\n\nand \n\n{\n  \u0027overcloud\u0027: {\n    configDownloadMessages: List(),\n    message: undefined,\n    status: \u0027UNDEPLOYED\u0027,\n    type: undefined\n  },\n  \u0027othercloud\u0027: {\n    configDownloadMessages: List(),\n    message: undefined,\n    status: \u0027UNDEPLOYED\u0027,\n    type: undefined\n  }\n}\n\nI know that it is different from what we usually do in the other places, but I think this is a good case to introduce this. It makes the reducer code much simpler. It does not matter that there are several reducers handling same actions. That\u0027s perfectly fine in Redux. Actions notify that something happened in app, reducers ensure that their chunk of app state is updated when relevant action happens.\n\nSee https://egghead.io/lessons/javascript-redux-normalizing-the-state-shape it was really helpful for me to watch.","commit_id":"a50d4b71dc14f7213d1659fe993b729a4c7607df"}],"src/js/reducers/deploymentStatus.js":[{"author":{"_account_id":20970,"name":"Honza Pokorny","email":"honza@redhat.com","username":"hpokorny"},"change_message_id":"c3ad8d36e1972627bcdcbd28cded89ac8ad26fd3","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"bf659307_1ff8757a","updated":"2018-04-05 13:37:53.000000000","message":"I don\u0027t like the reducers being separate like that.  Especially since you\u0027re matching on the same values in both.  It makes it so you have to check in both places when making changes.","commit_id":"a54416610a2d3fd881f5b03f3bb7f617edce4896"},{"author":{"_account_id":7509,"name":"Jiri Tomasek","email":"jtomasek@redhat.com","username":"jtomasek"},"change_message_id":"a4e7eb5a6caf090743c13bbbe60cfbf81d3b35b7","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"bf659307_71ad1330","in_reply_to":"bf659307_1ff8757a","updated":"2018-04-06 09:14:12.000000000","message":"What I like about it is how it separates the UI state from deployment state. deploymentStatusByPlan reducer is going to also handle other actions such as START_DEPLOYMENT_* etc.\n\nIn general reducers are supposed to handle certain branch of the app state and the actions don\u0027t need to resemble to reducers 1:1. This is going to occur for deployments and plans too. various deployment actions will be handled by both plans reducer and deployment status reducers.\n\nI am going to keep this patch WIP too and once I have progressed with follow up patches we\u0027ll have a better view whether it is good idea to split the reducer","commit_id":"a54416610a2d3fd881f5b03f3bb7f617edce4896"},{"author":{"_account_id":20970,"name":"Honza Pokorny","email":"honza@redhat.com","username":"hpokorny"},"change_message_id":"151dbe10ab62e9ffa9a50045a32e0d19e4731b08","unresolved":false,"context_lines":[{"line_number":33,"context_line":"  DeploymentStatusUI"},{"line_number":34,"context_line":"} from \u0027../immutableRecords/deploymentStatus\u0027;"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":"export const deploymentStatusByPlan \u003d (state \u003d Map(), { type, payload }) \u003d\u003e {"},{"line_number":37,"context_line":"  switch (type) {"},{"line_number":38,"context_line":"    case GET_DEPLOYMENT_STATUS_FAILED:"},{"line_number":39,"context_line":"      return state.set("}],"source_content_type":"text/javascript","patch_set":14,"id":"5f7c97a3_f6073917","line":36,"range":{"start_line":36,"start_character":29,"end_line":36,"end_character":31},"updated":"2018-05-14 16:53:25.000000000","message":"Nit: The word \"by\" seems to imply a selector or a filter of some kind.  What about \"planDeployStatus\" or \"deploymentStatusForPlan\"?","commit_id":"a50d4b71dc14f7213d1659fe993b729a4c7607df"},{"author":{"_account_id":7509,"name":"Jiri Tomasek","email":"jtomasek@redhat.com","username":"jtomasek"},"change_message_id":"c99533620aab6ac62359cdeb0f059ca22e233b06","unresolved":false,"context_lines":[{"line_number":33,"context_line":"  DeploymentStatusUI"},{"line_number":34,"context_line":"} from \u0027../immutableRecords/deploymentStatus\u0027;"},{"line_number":35,"context_line":""},{"line_number":36,"context_line":"export const deploymentStatusByPlan \u003d (state \u003d Map(), { type, payload }) \u003d\u003e {"},{"line_number":37,"context_line":"  switch (type) {"},{"line_number":38,"context_line":"    case GET_DEPLOYMENT_STATUS_FAILED:"},{"line_number":39,"context_line":"      return state.set("}],"source_content_type":"text/javascript","patch_set":14,"id":"5f7c97a3_b39d3d0b","line":36,"range":{"start_line":36,"start_character":29,"end_line":36,"end_character":31},"in_reply_to":"5f7c97a3_f6073917","updated":"2018-05-15 11:51:55.000000000","message":"I think the reducer name should describe which chunk of state it handles. How about \u0027deploymentStatusesByPlan\u0027? The second reducer should be then called deploymentStatusUIsByPlan\u0027 ? We could maybe remove byPlan part. Naming is hard, any better ideas?","commit_id":"a50d4b71dc14f7213d1659fe993b729a4c7607df"}],"src/js/services/errors/index.js":[{"author":{"_account_id":20970,"name":"Honza Pokorny","email":"honza@redhat.com","username":"hpokorny"},"change_message_id":"c3ad8d36e1972627bcdcbd28cded89ac8ad26fd3","unresolved":false,"context_lines":[{"line_number":57,"context_line":"}"},{"line_number":58,"context_line":""},{"line_number":59,"context_line":"class SwiftApiError extends BaseAxiosError {"},{"line_number":60,"context_line":"  constructor(e) {"},{"line_number":61,"context_line":"    const message \u003d `${e.response.status} - ${e.response.data}`;"},{"line_number":62,"context_line":"    super(\u0027SwiftApiError\u0027, message, e);"},{"line_number":63,"context_line":"  }"}],"source_content_type":"text/javascript","patch_set":4,"id":"bf659307_9f1245b4","line":60,"updated":"2018-04-05 13:37:53.000000000","message":"Why is this necessary?","commit_id":"a54416610a2d3fd881f5b03f3bb7f617edce4896"},{"author":{"_account_id":7509,"name":"Jiri Tomasek","email":"jtomasek@redhat.com","username":"jtomasek"},"change_message_id":"a4e7eb5a6caf090743c13bbbe60cfbf81d3b35b7","unresolved":false,"context_lines":[{"line_number":57,"context_line":"}"},{"line_number":58,"context_line":""},{"line_number":59,"context_line":"class SwiftApiError extends BaseAxiosError {"},{"line_number":60,"context_line":"  constructor(e) {"},{"line_number":61,"context_line":"    const message \u003d `${e.response.status} - ${e.response.data}`;"},{"line_number":62,"context_line":"    super(\u0027SwiftApiError\u0027, message, e);"},{"line_number":63,"context_line":"  }"}],"source_content_type":"text/javascript","patch_set":4,"id":"bf659307_916b07f0","line":60,"in_reply_to":"bf659307_9f1245b4","updated":"2018-04-06 09:14:12.000000000","message":"Not having this caused incorrect name for SwiftApiError. It was most probably introduced when we added explicit names for Errors.","commit_id":"a54416610a2d3fd881f5b03f3bb7f617edce4896"}]}
