summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/terraform
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-11-19 08:27:35 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-11-19 08:27:35 +0000
commit7e9c479f7de77702622631cff2628a9c8dcbc627 (patch)
treec8f718a08e110ad7e1894510980d2155a6549197 /app/assets/javascripts/terraform
parente852b0ae16db4052c1c567d9efa4facc81146e88 (diff)
downloadgitlab-ce-7e9c479f7de77702622631cff2628a9c8dcbc627.tar.gz
Add latest changes from gitlab-org/gitlab@13-6-stable-eev13.6.0-rc42
Diffstat (limited to 'app/assets/javascripts/terraform')
-rw-r--r--app/assets/javascripts/terraform/components/empty_state.vue44
-rw-r--r--app/assets/javascripts/terraform/components/states_table.vue101
-rw-r--r--app/assets/javascripts/terraform/components/terraform_list.vue134
-rw-r--r--app/assets/javascripts/terraform/constants.js1
-rw-r--r--app/assets/javascripts/terraform/graphql/fragments/state.fragment.graphql17
-rw-r--r--app/assets/javascripts/terraform/graphql/fragments/state_version.fragment.graphql9
-rw-r--r--app/assets/javascripts/terraform/graphql/queries/get_states.query.graphql18
-rw-r--r--app/assets/javascripts/terraform/index.js31
8 files changed, 355 insertions, 0 deletions
diff --git a/app/assets/javascripts/terraform/components/empty_state.vue b/app/assets/javascripts/terraform/components/empty_state.vue
new file mode 100644
index 00000000000..d86ba3af2b1
--- /dev/null
+++ b/app/assets/javascripts/terraform/components/empty_state.vue
@@ -0,0 +1,44 @@
+<script>
+import { GlEmptyState, GlIcon, GlLink, GlSprintf } from '@gitlab/ui';
+
+export default {
+ components: {
+ GlEmptyState,
+ GlIcon,
+ GlLink,
+ GlSprintf,
+ },
+ props: {
+ image: {
+ type: String,
+ required: true,
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-empty-state :svg-path="image" :title="s__('Terraform|Get started with Terraform')">
+ <template #description>
+ <p>
+ <gl-sprintf
+ :message="
+ s__(
+ 'Terraform|Find out how to use the %{linkStart}GitLab managed Terraform State%{linkEnd}',
+ )
+ "
+ >
+ <template #link="{ content }">
+ <gl-link
+ href="https://docs.gitlab.com/ee/user/infrastructure/index.html"
+ target="_blank"
+ >
+ {{ content }}
+ <gl-icon name="external-link" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </p>
+ </template>
+ </gl-empty-state>
+</template>
diff --git a/app/assets/javascripts/terraform/components/states_table.vue b/app/assets/javascripts/terraform/components/states_table.vue
new file mode 100644
index 00000000000..2e4c18c5a5b
--- /dev/null
+++ b/app/assets/javascripts/terraform/components/states_table.vue
@@ -0,0 +1,101 @@
+<script>
+import { GlBadge, GlIcon, GlSprintf, GlTable, GlTooltip } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
+import timeagoMixin from '~/vue_shared/mixins/timeago';
+
+export default {
+ components: {
+ GlBadge,
+ GlIcon,
+ GlSprintf,
+ GlTable,
+ GlTooltip,
+ TimeAgoTooltip,
+ },
+ mixins: [timeagoMixin],
+ props: {
+ states: {
+ required: true,
+ type: Array,
+ },
+ },
+ computed: {
+ fields() {
+ return [
+ {
+ key: 'name',
+ thClass: 'gl-display-none',
+ },
+ {
+ key: 'updated',
+ thClass: 'gl-display-none',
+ tdClass: 'gl-text-right',
+ },
+ ];
+ },
+ },
+ methods: {
+ createdByUserName(item) {
+ return item.latestVersion?.createdByUser?.name;
+ },
+ lockedByUserName(item) {
+ return item.lockedByUser?.name || s__('Terraform|Unknown User');
+ },
+ updatedTime(item) {
+ return item.latestVersion?.updatedAt || item.updatedAt;
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-table :items="states" :fields="fields" data-testid="terraform-states-table">
+ <template #cell(name)="{ item }">
+ <div class="gl-display-flex align-items-center" data-testid="terraform-states-table-name">
+ <p class="gl-font-weight-bold gl-m-0 gl-text-gray-900">
+ {{ item.name }}
+ </p>
+
+ <div v-if="item.lockedAt" id="terraformLockedBadgeContainer" class="gl-mx-2">
+ <gl-badge id="terraformLockedBadge">
+ <gl-icon name="lock" />
+ {{ s__('Terraform|Locked') }}
+ </gl-badge>
+
+ <gl-tooltip
+ container="terraformLockedBadgeContainer"
+ placement="right"
+ target="terraformLockedBadge"
+ >
+ <gl-sprintf :message="s__('Terraform|Locked by %{user} %{timeAgo}')">
+ <template #user>
+ {{ lockedByUserName(item) }}
+ </template>
+
+ <template #timeAgo>
+ {{ timeFormatted(item.lockedAt) }}
+ </template>
+ </gl-sprintf>
+ </gl-tooltip>
+ </div>
+ </div>
+ </template>
+
+ <template #cell(updated)="{ item }">
+ <p class="gl-m-0" data-testid="terraform-states-table-updated">
+ <gl-sprintf :message="s__('Terraform|%{user} updated %{timeAgo}')">
+ <template #user>
+ <span v-if="item.latestVersion">
+ {{ createdByUserName(item) }}
+ </span>
+ </template>
+
+ <template #timeAgo>
+ <time-ago-tooltip :time="updatedTime(item)" />
+ </template>
+ </gl-sprintf>
+ </p>
+ </template>
+ </gl-table>
+</template>
diff --git a/app/assets/javascripts/terraform/components/terraform_list.vue b/app/assets/javascripts/terraform/components/terraform_list.vue
new file mode 100644
index 00000000000..f614bdc8d43
--- /dev/null
+++ b/app/assets/javascripts/terraform/components/terraform_list.vue
@@ -0,0 +1,134 @@
+<script>
+import { GlAlert, GlBadge, GlKeysetPagination, GlLoadingIcon, GlTab, GlTabs } from '@gitlab/ui';
+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: {
+ states: {
+ query: getStatesQuery,
+ variables() {
+ return {
+ projectPath: this.projectPath,
+ ...this.cursor,
+ };
+ },
+ update: data => {
+ return {
+ count: data?.project?.terraformStates?.count,
+ list: data?.project?.terraformStates?.nodes,
+ pageInfo: data?.project?.terraformStates?.pageInfo,
+ };
+ },
+ error() {
+ this.states = null;
+ },
+ },
+ },
+ components: {
+ EmptyState,
+ GlAlert,
+ GlBadge,
+ GlKeysetPagination,
+ GlLoadingIcon,
+ GlTab,
+ GlTabs,
+ StatesTable,
+ },
+ props: {
+ emptyStateImage: {
+ required: true,
+ type: String,
+ },
+ projectPath: {
+ required: true,
+ type: String,
+ },
+ },
+ data() {
+ return {
+ cursor: {
+ first: MAX_LIST_COUNT,
+ after: null,
+ last: null,
+ before: null,
+ },
+ };
+ },
+ computed: {
+ isLoading() {
+ return this.$apollo.queries.states.loading;
+ },
+ pageInfo() {
+ return this.states?.pageInfo || {};
+ },
+ showPagination() {
+ return this.pageInfo.hasPreviousPage || this.pageInfo.hasNextPage;
+ },
+ statesCount() {
+ return this.states?.count;
+ },
+ statesList() {
+ return this.states?.list;
+ },
+ },
+ methods: {
+ updatePagination(item) {
+ if (item === this.pageInfo.endCursor) {
+ this.cursor = {
+ first: MAX_LIST_COUNT,
+ after: item,
+ last: null,
+ before: null,
+ };
+ } else {
+ this.cursor = {
+ first: null,
+ after: null,
+ last: MAX_LIST_COUNT,
+ before: item,
+ };
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <section>
+ <gl-tabs>
+ <gl-tab>
+ <template slot="title">
+ <p class="gl-m-0">
+ {{ s__('Terraform|States') }}
+ <gl-badge v-if="statesCount">{{ statesCount }}</gl-badge>
+ </p>
+ </template>
+
+ <gl-loading-icon v-if="isLoading" size="md" class="gl-mt-3" />
+
+ <div v-else-if="statesList">
+ <div v-if="statesCount">
+ <states-table :states="statesList" />
+
+ <div v-if="showPagination" class="gl-display-flex gl-justify-content-center gl-mt-5">
+ <gl-keyset-pagination
+ v-bind="pageInfo"
+ @prev="updatePagination"
+ @next="updatePagination"
+ />
+ </div>
+ </div>
+
+ <empty-state v-else :image="emptyStateImage" />
+ </div>
+
+ <gl-alert v-else variant="danger" :dismissible="false">
+ {{ s__('Terraform|An error occurred while loading your Terraform States') }}
+ </gl-alert>
+ </gl-tab>
+ </gl-tabs>
+ </section>
+</template>
diff --git a/app/assets/javascripts/terraform/constants.js b/app/assets/javascripts/terraform/constants.js
new file mode 100644
index 00000000000..bbc4630f83b
--- /dev/null
+++ b/app/assets/javascripts/terraform/constants.js
@@ -0,0 +1 @@
+export const MAX_LIST_COUNT = 25;
diff --git a/app/assets/javascripts/terraform/graphql/fragments/state.fragment.graphql b/app/assets/javascripts/terraform/graphql/fragments/state.fragment.graphql
new file mode 100644
index 00000000000..49f9ae3dd97
--- /dev/null
+++ b/app/assets/javascripts/terraform/graphql/fragments/state.fragment.graphql
@@ -0,0 +1,17 @@
+#import "~/graphql_shared/fragments/user.fragment.graphql"
+#import "./state_version.fragment.graphql"
+
+fragment State on TerraformState {
+ id
+ name
+ lockedAt
+ updatedAt
+
+ lockedByUser {
+ ...User
+ }
+
+ latestVersion {
+ ...StateVersion
+ }
+}
diff --git a/app/assets/javascripts/terraform/graphql/fragments/state_version.fragment.graphql b/app/assets/javascripts/terraform/graphql/fragments/state_version.fragment.graphql
new file mode 100644
index 00000000000..c7e9700c696
--- /dev/null
+++ b/app/assets/javascripts/terraform/graphql/fragments/state_version.fragment.graphql
@@ -0,0 +1,9 @@
+#import "~/graphql_shared/fragments/user.fragment.graphql"
+
+fragment StateVersion on TerraformStateVersion {
+ updatedAt
+
+ createdByUser {
+ ...User
+ }
+}
diff --git a/app/assets/javascripts/terraform/graphql/queries/get_states.query.graphql b/app/assets/javascripts/terraform/graphql/queries/get_states.query.graphql
new file mode 100644
index 00000000000..9453e32b1b5
--- /dev/null
+++ b/app/assets/javascripts/terraform/graphql/queries/get_states.query.graphql
@@ -0,0 +1,18 @@
+#import "../fragments/state.fragment.graphql"
+#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
+
+query getStates($projectPath: ID!, $first: Int, $last: Int, $before: String, $after: String) {
+ project(fullPath: $projectPath) {
+ terraformStates(first: $first, last: $last, before: $before, after: $after) {
+ count
+
+ nodes {
+ ...State
+ }
+
+ pageInfo {
+ ...PageInfo
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/terraform/index.js b/app/assets/javascripts/terraform/index.js
new file mode 100644
index 00000000000..579d2d14023
--- /dev/null
+++ b/app/assets/javascripts/terraform/index.js
@@ -0,0 +1,31 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import TerraformList from './components/terraform_list.vue';
+import createDefaultClient from '~/lib/graphql';
+
+Vue.use(VueApollo);
+
+export default () => {
+ const el = document.querySelector('#js-terraform-list');
+
+ if (!el) {
+ return null;
+ }
+
+ const defaultClient = createDefaultClient();
+
+ const { emptyStateImage, projectPath } = el.dataset;
+
+ return new Vue({
+ el,
+ apolloProvider: new VueApollo({ defaultClient }),
+ render(createElement) {
+ return createElement(TerraformList, {
+ props: {
+ emptyStateImage,
+ projectPath,
+ },
+ });
+ },
+ });
+};