environment.vue 7.93 KB
Newer Older
1
<script>
2
/* global Flash */
3
import Visibility from 'visibilityjs';
4
import EnvironmentsService from '../services/environments_service';
5
import environmentTable from './environments_table.vue';
6
import EnvironmentsStore from '../stores/environments_store';
7
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
8
import tablePagination from '../../vue_shared/components/table_pagination.vue';
9
import '../../lib/utils/common_utils';
10
import eventHub from '../event_hub';
11 12
import Poll from '../../lib/utils/poll';
import environmentsMixin from '../mixins/environments_mixin';
13

14
export default {
15 16

  components: {
17 18
    environmentTable,
    tablePagination,
19
    loadingIcon,
20 21
  },

22 23 24 25
  mixins: [
    environmentsMixin,
  ],

26 27
  data() {
    const environmentsData = document.querySelector('#environments-list-view').dataset;
Filipa Lacerda's avatar
Filipa Lacerda committed
28
    const store = new EnvironmentsStore();
29 30 31 32 33 34

    return {
      store,
      state: store.state,
      visibility: 'available',
      isLoading: false,
35
      isLoadingFolderContent: false,
36 37 38 39 40 41 42 43 44
      cssContainerClass: environmentsData.cssClass,
      endpoint: environmentsData.environmentsDataEndpoint,
      canCreateDeployment: environmentsData.canCreateDeployment,
      canReadEnvironment: environmentsData.canReadEnvironment,
      canCreateEnvironment: environmentsData.canCreateEnvironment,
      projectEnvironmentsPath: environmentsData.projectEnvironmentsPath,
      projectStoppedEnvironmentsPath: environmentsData.projectStoppedEnvironmentsPath,
      newEnvironmentPath: environmentsData.newEnvironmentPath,
      helpPagePath: environmentsData.helpPagePath,
45
      isMakingRequest: false,
Filipa Lacerda's avatar
Filipa Lacerda committed
46 47 48 49

      // Pagination Properties,
      paginationInformation: {},
      pageNumber: 1,
50 51 52 53 54
    };
  },

  computed: {
    scope() {
55
      return gl.utils.getParameterByName('scope');
Filipa Lacerda's avatar
Filipa Lacerda committed
56 57
    },

58
    canReadEnvironmentParsed() {
59
      return gl.utils.convertPermissionToBoolean(this.canReadEnvironment);
Filipa Lacerda's avatar
Filipa Lacerda committed
60 61
    },

62
    canCreateDeploymentParsed() {
63
      return gl.utils.convertPermissionToBoolean(this.canCreateDeployment);
Filipa Lacerda's avatar
Filipa Lacerda committed
64 65
    },

66
    canCreateEnvironmentParsed() {
67
      return gl.utils.convertPermissionToBoolean(this.canCreateEnvironment);
Filipa Lacerda's avatar
Filipa Lacerda committed
68
    },
69 70 71 72 73 74 75
  },

  /**
   * Fetches all the environments and stores them.
   * Toggles loading property.
   */
  created() {
76 77 78
    const scope = gl.utils.getParameterByName('scope') || this.visibility;
    const page = gl.utils.getParameterByName('page') || this.pageNumber;

79 80
    this.service = new EnvironmentsService(this.endpoint);

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
    const poll = new Poll({
      resource: this.service,
      method: 'get',
      data: { scope, page },
      successCallback: this.successCallback,
      errorCallback: this.errorCallback,
      notificationCallback: (isMakingRequest) => {
        this.isMakingRequest = isMakingRequest;

        // We need to verify if any folder is open to also fecth it
        this.openFolders = this.store.getOpenFolders();
      },
    });

    if (!Visibility.hidden()) {
      this.isLoading = true;
      poll.makeRequest();
    }

    Visibility.change(() => {
      if (!Visibility.hidden()) {
        poll.restart();
      } else {
        poll.stop();
      }
    });
107

108
    eventHub.$on('toggleFolder', this.toggleFolder);
109
    eventHub.$on('postAction', this.postAction);
110 111
  },

112
  beforeDestroy() {
113
    eventHub.$off('toggleFolder');
Filipa Lacerda's avatar
Filipa Lacerda committed
114
    eventHub.$off('postAction');
115 116 117
  },

  methods: {
Filipa Lacerda's avatar
Filipa Lacerda committed
118
    toggleFolder(folder, folderUrl) {
119 120 121
      this.store.toggleFolder(folder);

      if (!folder.isOpen) {
Filipa Lacerda's avatar
Filipa Lacerda committed
122
        this.fetchChildEnvironments(folder, folderUrl);
123
      }
Filipa Lacerda's avatar
Filipa Lacerda committed
124
    },
Filipa Lacerda's avatar
Filipa Lacerda committed
125

126 127 128 129
    /**
     * Will change the page number and update the URL.
     *
     * @param  {Number} pageNumber desired page to go to.
130
     * @return {String}
131 132
     */
    changePage(pageNumber) {
133
      const param = gl.utils.setParamInURL('page', pageNumber);
134

135
      gl.utils.visitUrl(param);
136
      return param;
Filipa Lacerda's avatar
Filipa Lacerda committed
137
    },
138 139 140

    fetchEnvironments() {
      const scope = gl.utils.getParameterByName('scope') || this.visibility;
141
      const page = gl.utils.getParameterByName('page') || this.pageNumber;
142 143 144

      this.isLoading = true;

145 146 147
      return this.service.get({ scope, page })
        .then(this.successCallback)
        .catch(this.errorCallback);
148
    },
149

Filipa Lacerda's avatar
Filipa Lacerda committed
150
    fetchChildEnvironments(folder, folderUrl) {
151 152
      this.isLoadingFolderContent = true;

Filipa Lacerda's avatar
Filipa Lacerda committed
153
      this.service.getFolderContent(folderUrl)
154 155
        .then(resp => resp.json())
        .then((response) => {
Filipa Lacerda's avatar
Filipa Lacerda committed
156
          this.store.setfolderContent(folder, response.environments);
157 158 159 160
          this.isLoadingFolderContent = false;
        })
        .catch(() => {
          this.isLoadingFolderContent = false;
161
          // eslint-disable-next-line no-new
162 163 164
          new Flash('An error occurred while fetching the environments.');
        });
    },
165 166

    postAction(endpoint) {
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
      if (!this.isMakingRequest) {
        this.isLoading = true;

        this.service.postAction(endpoint)
          .then(() => this.fetchEnvironments())
          .catch(() => new Flash('An error occured while making the request.'));
      }
    },

    successCallback(resp) {
      this.saveData(resp);

      // If folders are open while polling we need to open them again
      if (this.openFolders.length) {
        this.openFolders.map((folder) => {
          // TODO - Move this to the backend
          const folderUrl = `${window.location.pathname}/folders/${folder.folderName}`;

          this.store.updateFolder(folder, 'isOpen', true);
          return this.fetchChildEnvironments(folder, folderUrl);
        });
      }
    },

    errorCallback() {
      this.isLoading = false;
      // eslint-disable-next-line no-new
      new Flash('An error occurred while fetching the environments.');
195
    },
196
  },
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
};
</script>
<template>
  <div :class="cssContainerClass">
    <div class="top-area">
      <ul
        v-if="!isLoading"
        class="nav-links">
        <li :class="{ active: scope === null || scope === 'available' }">
          <a :href="projectEnvironmentsPath">
            Available
            <span class="badge js-available-environments-count">
              {{state.availableCounter}}
            </span>
          </a>
        </li>
        <li :class="{ active : scope === 'stopped' }">
          <a :href="projectStoppedEnvironmentsPath">
            Stopped
            <span class="badge js-stopped-environments-count">
              {{state.stoppedCounter}}
            </span>
219
          </a>
220 221 222 223 224 225 226 227 228 229
        </li>
      </ul>
      <div
        v-if="canCreateEnvironmentParsed && !isLoading"
        class="nav-controls">
        <a
          :href="newEnvironmentPath"
          class="btn btn-create">
          New environment
        </a>
230
      </div>
231 232
    </div>

233
    <div class="environments-container">
234 235 236 237 238
      <loading-icon
        label="Loading environments"
        size="3"
        v-if="isLoading"
        />
239 240 241 242 243 244 245 246 247 248 249 250

      <div
        class="blank-state blank-state-no-icon"
        v-if="!isLoading && state.environments.length === 0">
        <h2 class="blank-state-title js-blank-state-title">
          You don't have any environments right now.
        </h2>
        <p class="blank-state-text">
          Environments are places where code gets deployed, such as staging or production.
          <br />
          <a :href="helpPagePath">
            Read more about environments
251
          </a>
252 253 254 255 256 257
        </p>

        <a
          v-if="canCreateEnvironmentParsed"
          :href="newEnvironmentPath"
          class="btn btn-create js-new-environment-button">
258
          New environment
259
        </a>
Filipa Lacerda's avatar
Filipa Lacerda committed
260
      </div>
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276

      <div
        class="table-holder"
        v-if="!isLoading && state.environments.length > 0">

        <environment-table
          :environments="state.environments"
          :can-create-deployment="canCreateDeploymentParsed"
          :can-read-environment="canReadEnvironmentParsed"
          :is-loading-folder-content="isLoadingFolderContent" />
      </div>

      <table-pagination
        v-if="state.paginationInformation && state.paginationInformation.totalPages > 1"
        :change="changePage"
        :pageInfo="state.paginationInformation" />
277
    </div>
278 279
  </div>
</template>