diff options
author | Enrique Alcántara <ealcantara@gitlab.com> | 2019-04-26 08:15:44 +0000 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2019-04-26 08:15:44 +0000 |
commit | 690382dda6d7404d702276413f907d5744498fde (patch) | |
tree | 8eba5d2bc72923bde41a75582f970aa53a8bece2 /app/assets/javascripts/clusters/services | |
parent | 336a0a8745e7eb1bb38c6f6f0ec7832569b041bf (diff) | |
download | gitlab-ce-690382dda6d7404d702276413f907d5744498fde.tar.gz |
Use a FSM to determine application next state
- Separate cluster application UI state from server-side app status
- Use a state machine to determine cluster application next state
- Instead of using two variables to keep track of when an app
is installing or updating, just use the app status property and control
server-side and user events using the FSM service.
Diffstat (limited to 'app/assets/javascripts/clusters/services')
-rw-r--r-- | app/assets/javascripts/clusters/services/application_state_machine.js | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/app/assets/javascripts/clusters/services/application_state_machine.js b/app/assets/javascripts/clusters/services/application_state_machine.js new file mode 100644 index 00000000000..aafb2350ae4 --- /dev/null +++ b/app/assets/javascripts/clusters/services/application_state_machine.js @@ -0,0 +1,141 @@ +import { APPLICATION_STATUS, UPDATE_EVENT, INSTALL_EVENT } from '../constants'; + +const { + NO_STATUS, + SCHEDULED, + NOT_INSTALLABLE, + INSTALLABLE, + INSTALLING, + INSTALLED, + ERROR, + UPDATING, + UPDATED, + UPDATE_ERRORED, +} = APPLICATION_STATUS; + +const applicationStateMachine = { + /* When the application initially loads, it will have `NO_STATUS` + * It will transition from `NO_STATUS` once the async backend call is completed + */ + [NO_STATUS]: { + on: { + [SCHEDULED]: { + target: INSTALLING, + }, + [NOT_INSTALLABLE]: { + target: NOT_INSTALLABLE, + }, + [INSTALLABLE]: { + target: INSTALLABLE, + }, + [INSTALLING]: { + target: INSTALLING, + }, + [INSTALLED]: { + target: INSTALLED, + }, + [ERROR]: { + target: INSTALLABLE, + effects: { + installFailed: true, + }, + }, + [UPDATING]: { + target: UPDATING, + }, + [UPDATED]: { + target: INSTALLED, + }, + [UPDATE_ERRORED]: { + target: INSTALLED, + effects: { + updateFailed: true, + }, + }, + }, + }, + [NOT_INSTALLABLE]: { + on: { + [INSTALLABLE]: { + target: INSTALLABLE, + }, + }, + }, + [INSTALLABLE]: { + on: { + [INSTALL_EVENT]: { + target: INSTALLING, + effects: { + installFailed: false, + }, + }, + // This is possible in artificial environments for E2E testing + [INSTALLED]: { + target: INSTALLED, + }, + }, + }, + [INSTALLING]: { + on: { + [INSTALLED]: { + target: INSTALLED, + }, + [ERROR]: { + target: INSTALLABLE, + effects: { + installFailed: true, + }, + }, + }, + }, + [INSTALLED]: { + on: { + [UPDATE_EVENT]: { + target: UPDATING, + effects: { + updateFailed: false, + updateSuccessful: false, + }, + }, + }, + }, + [UPDATING]: { + on: { + [UPDATED]: { + target: INSTALLED, + effects: { + updateSuccessful: true, + updateAcknowledged: false, + }, + }, + [UPDATE_ERRORED]: { + target: INSTALLED, + effects: { + updateFailed: true, + }, + }, + }, + }, +}; + +/** + * Determines an application new state based on the application current state + * and an event. If the application current state cannot handle a given event, + * the current state is returned. + * + * @param {*} application + * @param {*} event + */ +const transitionApplicationState = (application, event) => { + const newState = applicationStateMachine[application.status].on[event]; + + return newState + ? { + ...application, + status: newState.target, + ...newState.effects, + } + : application; +}; + +export default transitionApplicationState; |