Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 13:34:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 13:34:06 +0300
commit859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 (patch)
treed7f2700abe6b4ffcb2dcfc80631b2d87d0609239 /app/assets/javascripts/terraform
parent446d496a6d000c73a304be52587cd9bbc7493136 (diff)
Add latest changes from gitlab-org/gitlab@13-9-stable-eev13.9.0-rc42
Diffstat (limited to 'app/assets/javascripts/terraform')
-rw-r--r--app/assets/javascripts/terraform/components/states_table.vue62
-rw-r--r--app/assets/javascripts/terraform/components/states_table_actions.vue80
-rw-r--r--app/assets/javascripts/terraform/components/terraform_list.vue2
-rw-r--r--app/assets/javascripts/terraform/graphql/fragments/state.fragment.graphql5
-rw-r--r--app/assets/javascripts/terraform/graphql/mutations/add_data_to_state.mutation.graphql3
-rw-r--r--app/assets/javascripts/terraform/graphql/resolvers.js45
-rw-r--r--app/assets/javascripts/terraform/index.js14
7 files changed, 194 insertions, 17 deletions
diff --git a/app/assets/javascripts/terraform/components/states_table.vue b/app/assets/javascripts/terraform/components/states_table.vue
index d0d49233334..2577664a5e8 100644
--- a/app/assets/javascripts/terraform/components/states_table.vue
+++ b/app/assets/javascripts/terraform/components/states_table.vue
@@ -1,18 +1,29 @@
<script>
-import { GlBadge, GlIcon, GlLink, GlSprintf, GlTable, GlTooltip } from '@gitlab/ui';
-import { s__ } from '~/locale';
+import {
+ GlAlert,
+ GlBadge,
+ GlIcon,
+ GlLink,
+ GlLoadingIcon,
+ GlSprintf,
+ GlTable,
+ GlTooltip,
+} from '@gitlab/ui';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { s__ } from '~/locale';
import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
-import StateActions from './states_table_actions.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
+import StateActions from './states_table_actions.vue';
export default {
components: {
CiBadge,
+ GlAlert,
GlBadge,
GlIcon,
GlLink,
+ GlLoadingIcon,
GlSprintf,
GlTable,
GlTooltip,
@@ -66,15 +77,21 @@ export default {
jobStatus: s__('Terraform|Job status'),
locked: s__('Terraform|Locked'),
lockedByUser: s__('Terraform|Locked by %{user} %{timeAgo}'),
+ lockingState: s__('Terraform|Locking state'),
name: s__('Terraform|Name'),
pipeline: s__('Terraform|Pipeline'),
+ removing: s__('Terraform|Removing'),
unknownUser: s__('Terraform|Unknown User'),
+ unlockingState: s__('Terraform|Unlocking state'),
updatedUser: s__('Terraform|%{user} updated %{timeAgo}'),
},
methods: {
createdByUserName(item) {
return item.latestVersion?.createdByUser?.name;
},
+ loadingLockText(item) {
+ return item.lockedAt ? this.$options.i18n.unlockingState : this.$options.i18n.lockingState;
+ },
lockedByUserName(item) {
return item.lockedByUser?.name || this.$options.i18n.unknownUser;
},
@@ -105,6 +122,7 @@ export default {
:items="states"
:fields="fields"
data-testid="terraform-states-table"
+ details-td-class="gl-p-0!"
fixed
stacked="md"
>
@@ -117,7 +135,27 @@ export default {
{{ item.name }}
</p>
- <div v-if="item.lockedAt" :id="`terraformLockedBadgeContainer${item.name}`" class="gl-mx-2">
+ <div v-if="item.loadingLock" class="gl-mx-3">
+ <p class="gl-display-flex gl-justify-content-start gl-align-items-baseline gl-m-0">
+ <gl-loading-icon class="gl-pr-1" />
+ {{ loadingLockText(item) }}
+ </p>
+ </div>
+
+ <div v-else-if="item.loadingRemove" class="gl-mx-3">
+ <p
+ class="gl-display-flex gl-justify-content-start gl-align-items-baseline gl-m-0 gl-text-red-500"
+ >
+ <gl-loading-icon class="gl-pr-1" />
+ {{ $options.i18n.removing }}
+ </p>
+ </div>
+
+ <div
+ v-else-if="item.lockedAt"
+ :id="`terraformLockedBadgeContainer${item.name}`"
+ class="gl-mx-3"
+ >
<gl-badge :id="`terraformLockedBadge${item.name}`">
<gl-icon name="lock" />
{{ $options.i18n.locked }}
@@ -189,5 +227,21 @@ export default {
<template v-if="terraformAdmin" #cell(actions)="{ item }">
<state-actions :state="item" />
</template>
+
+ <template #row-details="row">
+ <gl-alert
+ data-testid="terraform-states-table-error"
+ variant="danger"
+ @dismiss="row.toggleDetails"
+ >
+ <span
+ v-for="errorMessage in row.item.errorMessages"
+ :key="errorMessage"
+ class="gl-display-flex gl-justify-content-start"
+ >
+ {{ errorMessage }}
+ </span>
+ </gl-alert>
+ </template>
</gl-table>
</template>
diff --git a/app/assets/javascripts/terraform/components/states_table_actions.vue b/app/assets/javascripts/terraform/components/states_table_actions.vue
index 44b0713e544..c4fd97188de 100644
--- a/app/assets/javascripts/terraform/components/states_table_actions.vue
+++ b/app/assets/javascripts/terraform/components/states_table_actions.vue
@@ -9,10 +9,11 @@ import {
GlModal,
GlSprintf,
} from '@gitlab/ui';
-import { s__ } from '~/locale';
+import { s__, sprintf } from '~/locale';
+import addDataToState from '../graphql/mutations/add_data_to_state.mutation.graphql';
import lockState from '../graphql/mutations/lock_state.mutation.graphql';
-import unlockState from '../graphql/mutations/unlock_state.mutation.graphql';
import removeState from '../graphql/mutations/remove_state.mutation.graphql';
+import unlockState from '../graphql/mutations/unlock_state.mutation.graphql';
export default {
components: {
@@ -33,13 +34,13 @@ export default {
},
data() {
return {
- loading: false,
showRemoveModal: false,
removeConfirmText: '',
};
},
i18n: {
downloadJSON: s__('Terraform|Download JSON'),
+ errorUpdate: s__('Terraform|An error occurred while changing the state file'),
lock: s__('Terraform|Lock'),
modalBody: s__(
'Terraform|You are about to remove the State file %{name}. This will permanently delete all the State versions and history. The infrastructure provisioned previously will remain intact, only the state file with all its versions are to be removed. This action is non-revertible.',
@@ -51,6 +52,7 @@ export default {
),
modalRemove: s__('Terraform|Remove'),
remove: s__('Terraform|Remove state file and versions'),
+ removeSuccessful: s__('Terraform|%{name} successfully removed'),
unlock: s__('Terraform|Unlock'),
},
computed: {
@@ -63,6 +65,9 @@ export default {
disableModalSubmit() {
return this.removeConfirmText !== this.state.name;
},
+ loading() {
+ return this.state.loadingLock || this.state.loadingRemove;
+ },
primaryModalProps() {
return {
text: this.$options.i18n.modalRemove,
@@ -76,19 +81,56 @@ export default {
this.removeConfirmText = '';
},
lock() {
- this.stateMutation(lockState);
+ this.updateStateCache({
+ _showDetails: false,
+ errorMessages: [],
+ loadingLock: true,
+ loadingRemove: false,
+ });
+
+ this.stateActionMutation(lockState);
},
unlock() {
- this.stateMutation(unlockState);
+ this.updateStateCache({
+ _showDetails: false,
+ errorMessages: [],
+ loadingLock: true,
+ loadingRemove: false,
+ });
+
+ this.stateActionMutation(unlockState);
+ },
+ updateStateCache(newData) {
+ this.$apollo.mutate({
+ mutation: addDataToState,
+ variables: {
+ terraformState: {
+ ...this.state,
+ ...newData,
+ },
+ },
+ });
},
remove() {
if (!this.disableModalSubmit) {
this.hideModal();
- this.stateMutation(removeState);
+
+ this.updateStateCache({
+ _showDetails: false,
+ errorMessages: [],
+ loadingLock: false,
+ loadingRemove: true,
+ });
+
+ this.stateActionMutation(
+ removeState,
+ sprintf(this.$options.i18n.removeSuccessful, { name: this.state.name }),
+ );
}
},
- stateMutation(mutation) {
- this.loading = true;
+ stateActionMutation(mutation, successMessage = null) {
+ let errorMessages = [];
+
this.$apollo
.mutate({
mutation,
@@ -99,9 +141,27 @@ export default {
awaitRefetchQueries: true,
notifyOnNetworkStatusChange: true,
})
- .catch(() => {})
+ .then(({ data }) => {
+ errorMessages =
+ data?.terraformStateDelete?.errors ||
+ data?.terraformStateLock?.errors ||
+ data?.terraformStateUnlock?.errors ||
+ [];
+
+ if (errorMessages.length === 0 && successMessage) {
+ this.$toast.show(successMessage);
+ }
+ })
+ .catch(() => {
+ errorMessages = [this.$options.i18n.errorUpdate];
+ })
.finally(() => {
- this.loading = false;
+ this.updateStateCache({
+ _showDetails: Boolean(errorMessages.length),
+ errorMessages,
+ loadingLock: false,
+ loadingRemove: false,
+ });
});
},
},
diff --git a/app/assets/javascripts/terraform/components/terraform_list.vue b/app/assets/javascripts/terraform/components/terraform_list.vue
index b71133d8813..a18f33ebb1f 100644
--- a/app/assets/javascripts/terraform/components/terraform_list.vue
+++ b/app/assets/javascripts/terraform/components/terraform_list.vue
@@ -1,9 +1,9 @@
<script>
import { GlAlert, GlBadge, GlKeysetPagination, GlLoadingIcon, GlTab, GlTabs } from '@gitlab/ui';
+import { MAX_LIST_COUNT } from '../constants';
import getStatesQuery from '../graphql/queries/get_states.query.graphql';
import EmptyState from './empty_state.vue';
import StatesTable from './states_table.vue';
-import { MAX_LIST_COUNT } from '../constants';
export default {
apollo: {
diff --git a/app/assets/javascripts/terraform/graphql/fragments/state.fragment.graphql b/app/assets/javascripts/terraform/graphql/fragments/state.fragment.graphql
index 49f9ae3dd97..fb823336411 100644
--- a/app/assets/javascripts/terraform/graphql/fragments/state.fragment.graphql
+++ b/app/assets/javascripts/terraform/graphql/fragments/state.fragment.graphql
@@ -2,6 +2,11 @@
#import "./state_version.fragment.graphql"
fragment State on TerraformState {
+ _showDetails @client
+ errorMessages @client
+ loadingLock @client
+ loadingRemove @client
+
id
name
lockedAt
diff --git a/app/assets/javascripts/terraform/graphql/mutations/add_data_to_state.mutation.graphql b/app/assets/javascripts/terraform/graphql/mutations/add_data_to_state.mutation.graphql
new file mode 100644
index 00000000000..645b9766e2b
--- /dev/null
+++ b/app/assets/javascripts/terraform/graphql/mutations/add_data_to_state.mutation.graphql
@@ -0,0 +1,3 @@
+mutation addDataToTerraformState($terraformState: State!) {
+ addDataToTerraformState(terraformState: $terraformState) @client
+}
diff --git a/app/assets/javascripts/terraform/graphql/resolvers.js b/app/assets/javascripts/terraform/graphql/resolvers.js
new file mode 100644
index 00000000000..d27379bdd9f
--- /dev/null
+++ b/app/assets/javascripts/terraform/graphql/resolvers.js
@@ -0,0 +1,45 @@
+import TerraformState from './fragments/state.fragment.graphql';
+
+export default {
+ TerraformState: {
+ _showDetails: (state) => {
+ // eslint-disable-next-line no-underscore-dangle
+ return state._showDetails || false;
+ },
+ errorMessages: (state) => {
+ return state.errorMessages || [];
+ },
+ loadingLock: (state) => {
+ return state.loadingLock || false;
+ },
+ loadingRemove: (state) => {
+ return state.loadingRemove || false;
+ },
+ },
+ Mutation: {
+ addDataToTerraformState: (_, { terraformState }, { client }) => {
+ const fragmentData = {
+ id: terraformState.id,
+ fragment: TerraformState,
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ fragmentName: 'State',
+ };
+
+ const previousTerraformState = client.readFragment(fragmentData);
+
+ if (previousTerraformState) {
+ client.writeFragment({
+ ...fragmentData,
+ data: {
+ ...previousTerraformState,
+ // eslint-disable-next-line no-underscore-dangle
+ _showDetails: terraformState._showDetails,
+ errorMessages: terraformState.errorMessages,
+ loadingLock: terraformState.loadingLock,
+ loadingRemove: terraformState.loadingRemove,
+ },
+ });
+ }
+ },
+ },
+};
diff --git a/app/assets/javascripts/terraform/index.js b/app/assets/javascripts/terraform/index.js
index e27a29433f3..3f986423836 100644
--- a/app/assets/javascripts/terraform/index.js
+++ b/app/assets/javascripts/terraform/index.js
@@ -1,8 +1,12 @@
+import { GlToast } from '@gitlab/ui';
+import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
-import TerraformList from './components/terraform_list.vue';
import createDefaultClient from '~/lib/graphql';
+import TerraformList from './components/terraform_list.vue';
+import resolvers from './graphql/resolvers';
+Vue.use(GlToast);
Vue.use(VueApollo);
export default () => {
@@ -12,7 +16,13 @@ export default () => {
return null;
}
- const defaultClient = createDefaultClient();
+ const defaultClient = createDefaultClient(resolvers, {
+ cacheConfig: {
+ dataIdFromObject: (object) => {
+ return object.id || defaultDataIdFromObject(object);
+ },
+ },
+ });
const { emptyStateImage, projectPath } = el.dataset;