summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/environments/stores/environments_store.js.es6
blob: 9b4090100da10016fea8abdeff257dcd814e2ae0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/* eslint-disable no-param-reassign */
(() => {
  window.gl = window.gl || {};
  window.gl.environmentsList = window.gl.environmentsList || {};

  gl.environmentsList.EnvironmentsStore = {
    state: {},

    create() {
      this.state.environments = [];
      this.state.stoppedCounter = 0;
      this.state.availableCounter = 0;
      this.state.visibility = 'available';
      this.state.filteredEnvironments = [];

      return this;
    },

    /**
     * In order to display a tree view we need to modify the received
     * data in to a tree structure based on `environment_type`
     * sorted alphabetically.
     * In each children a `vue-` property will be added. This property will be
     * used to know if an item is a children mostly for css purposes. This is
     * needed because the children row is a fragment instance and therfore does
     * not accept non-prop attributes.
     *
     *
     * @example
     * it will transform this:
     * [
     *   { name: "environment", environment_type: "review" },
     *   { name: "environment_1", environment_type: null }
     *   { name: "environment_2, environment_type: "review" }
     * ]
     * into this:
     * [
     *   { name: "review", children:
     *      [
     *        { name: "environment", environment_type: "review", vue-isChildren: true},
     *        { name: "environment_2", environment_type: "review", vue-isChildren: true}
     *      ]
     *   },
     *  {name: "environment_1", environment_type: null}
     * ]
     *
     *
     * @param  {Array} environments List of environments.
     * @returns {Array} Tree structured array with the received environments.
     */
    storeEnvironments(environments = []) {
      this.state.stoppedCounter = this.countByState(environments, 'stopped');
      this.state.availableCounter = this.countByState(environments, 'available');

      const environmentsTree = environments.reduce((acc, environment) => {
        if (environment.environment_type !== null) {
          const occurs = acc.filter(element => element.children &&
             element.name === environment.environment_type);

          environment['vue-isChildren'] = true;

          if (occurs.length) {
            acc[acc.indexOf(occurs[0])].children.push(environment);
            acc[acc.indexOf(occurs[0])].children.slice().sort(this.sortByName);
          } else {
            acc.push({
              name: environment.environment_type,
              children: [environment],
              isOpen: false,
              'vue-isChildren': environment['vue-isChildren'],
            });
          }
        } else {
          acc.push(environment);
        }

        return acc;
      }, []).slice().sort(this.sortByName);

      this.state.environments = environmentsTree;

      this.filterEnvironmentsByVisibility(this.state.environments);

      return environmentsTree;
    },

    storeVisibility(visibility) {
      this.state.visibility = visibility;
    },
    /**
     * Given the visibility prop provided by the url query parameter and which
     * changes according to the active tab we need to filter which environments
     * should be visible.
     *
     * The environments array is a recursive tree structure and we need to filter
     * both root level environments and children environments.
     *
     * In order to acomplish that, both `filterState` and `filterEnvironmentsByVisibility`
     * functions work together.
     * The first one works as the filter that verifies if the given environment matches
     * the given state.
     * The second guarantees both root level and children elements are filtered as well.
     *
     * Given array of environments will return only
     * the environments that match the state stored.
     *
     * @param {Array} array
     * @return {Array}
     */
    filterEnvironmentsByVisibility(arr) {
      const filteredEnvironments = arr.map((item) => {
        if (item.children) {
          const filteredChildren = this.filterEnvironmentsByVisibility(
            item.children,
          ).filter(Boolean);

          if (filteredChildren.length) {
            item.children = filteredChildren;
            return item;
          }
        }

        return this.filterState(this.state.visibility, item);
      }).filter(Boolean);

      this.state.filteredEnvironments = filteredEnvironments;
      return filteredEnvironments;
    },

    /**
     * Given the state and the environment,
     * returns only if the environment state matches the one provided.
     *
     * @param  {String} state
     * @param  {Object} environment
     * @return {Object}
     */
    filterState(state, environment) {
      return environment.state === state && environment;
    },

    /**
     * Toggles folder open property given the environment type.
     *
     * @param  {String} envType
     * @return {Array}
     */
    toggleFolder(envType) {
      const environments = this.state.environments;

      const environmentsCopy = environments.map((env) => {
        if (env['vue-isChildren'] && env.name === envType) {
          env.isOpen = !env.isOpen;
        }

        return env;
      });

      this.state.environments = environmentsCopy;

      return environmentsCopy;
    },

    /**
     * Given an array of environments, returns the number of environments
     * that have the given state.
     *
     * @param  {Array} environments
     * @param  {String} state
     * @returns {Number}
     */
    countByState(environments, state) {
      return environments.filter(env => env.state === state).length;
    },

    /**
     * Sorts the two objects provided by their name.
     *
     * @param  {Object} a
     * @param  {Object} b
     * @returns {Number}
     */
    sortByName(a, b) {
      const nameA = a.name.toUpperCase();
      const nameB = b.name.toUpperCase();

      return nameA < nameB ? -1 : nameA > nameB ? 1 : 0; // eslint-disable-line
    },
  };
})();