Commit b88fd0ac authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch 'incubation_5mp_google_cloud_frontend_new_service_account' into 'master'

Frontend for Google Cloud :: Service Accounts

See merge request gitlab-org/gitlab!74880
parents 49e3025e 00f8730e
<script>
import { GlAlert } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: { GlAlert },
props: {
error: {
type: String,
required: true,
},
},
i18n: {
title: __('Google Cloud project misconfigured'),
description: __(
'GitLab and Google Cloud configuration seems to be incomplete. This probably can be fixed by your GitLab administration team. You may share these logs with them:',
),
},
};
</script>
<template>
<gl-alert :dismissible="false" variant="warning" :title="$options.i18n.title">
{{ $options.i18n.description }}
<blockquote>
<code>{{ error }}</code>
</blockquote>
</gl-alert>
</template>
<script>
import { GlAlert, GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
components: { GlAlert, GlButton },
i18n: {
title: __('Google Cloud project required'),
description: __(
'You do not have any Google Cloud projects. Please create a Google Cloud project and then reload this page.',
),
createLabel: __('Create Google Cloud project'),
},
};
</script>
<template>
<gl-alert :dismissible="false" variant="warning" :title="$options.i18n.title">
{{ $options.i18n.description }}
<template #actions>
<gl-button href="https://console.cloud.google.com/projectcreate" target="_blank">
{{ $options.i18n.createLabel }}
</gl-button>
</template>
</gl-alert>
</template>
<script>
import { GlTab, GlTabs } from '@gitlab/ui';
import IncubationBanner from './incubation_banner.vue';
import ServiceAccounts from './service_accounts.vue';
import IncubationBanner from '../incubation_banner.vue';
import ServiceAccountsList from '../service_accounts_list.vue';
export default {
components: { GlTab, GlTabs, IncubationBanner, ServiceAccounts },
components: { GlTab, GlTabs, IncubationBanner, ServiceAccountsList },
props: {
serviceAccounts: {
type: Array,
......@@ -36,7 +36,7 @@ export default {
/>
<gl-tabs>
<gl-tab :title="__('Configuration')">
<service-accounts
<service-accounts-list
class="gl-mx-3"
:list="serviceAccounts"
:create-url="createServiceAccountUrl"
......
<script>
import { GlButton, GlFormGroup, GlFormSelect } from '@gitlab/ui';
import { __ } from '~/locale';
import IncubationBanner from '../incubation_banner.vue';
export default {
components: { GlButton, GlFormGroup, GlFormSelect, IncubationBanner },
props: {
gcpProjects: { required: true, type: Array },
environments: { required: true, type: Array },
cancelPath: { required: true, type: String },
},
methods: {
feedbackUrl(template) {
return `https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/meta/-/issues/new?issuable_template=${template}`;
},
},
i18n: {
title: __('Create service account'),
gcpProjectLabel: __('Google Cloud project'),
gcpProjectDescription: __(
'New service account is generated for the selected Google Cloud project',
),
environmentLabel: __('Environment'),
environmentDescription: __('Generated service account is linked to the selected environment'),
submitLabel: __('Create service account'),
cancelLabel: __('Cancel'),
},
};
</script>
<template>
<div>
<incubation-banner
:share-feedback-url="feedbackUrl('general_feedback')"
:report-bug-url="feedbackUrl('report_bug')"
:feature-request-url="feedbackUrl('feature_request')"
/>
<header class="gl-my-5 gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid">
<h2 class="gl-font-size-h1">{{ $options.i18n.title }}</h2>
</header>
<gl-form-group
label-for="gcp_project"
:label="$options.i18n.gcpProjectLabel"
:description="$options.i18n.gcpProjectDescription"
>
<gl-form-select id="gcp_project" name="gcp_project" required>
<option
v-for="gcpProject in gcpProjects"
:key="gcpProject.project_id"
:value="gcpProject.project_id"
>
{{ gcpProject.name }}
</option>
</gl-form-select>
</gl-form-group>
<gl-form-group
label-for="environment"
:label="$options.i18n.environmentLabel"
:description="$options.i18n.environmentDescription"
>
<gl-form-select id="environment" name="environment" required>
<option value="*">{{ __('All') }}</option>
<option
v-for="environment in environments"
:key="environment.name"
:value="environment.name"
>
{{ environment.name }}
</option>
</gl-form-select>
</gl-form-group>
<div class="form-actions row">
<gl-button type="submit" category="primary" variant="confirm">
{{ $options.i18n.submitLabel }}
</gl-button>
<gl-button class="gl-ml-1" :href="cancelPath">{{ $options.i18n.cancelLabel }}</gl-button>
</div>
</div>
</template>
import Vue from 'vue';
import App from './components/app.vue';
import { __ } from '~/locale';
import App from './components/screens/app.vue';
import ServiceAccountsForm from './components/screens/service_accounts_form.vue';
import ErrorNoGcpProjects from './components/errors/no_gcp_projects.vue';
import ErrorGcpError from './components/errors/gcp_error.vue';
const elementRenderer = (element, props = {}) => (createElement) =>
createElement(element, { props });
const rootComponentMap = [
{
root: '#js-google-cloud-error-no-gcp-projects',
component: ErrorNoGcpProjects,
},
{
root: '#js-google-cloud-error-gcp-error',
component: ErrorGcpError,
},
{
root: '#js-google-cloud-service-accounts',
component: ServiceAccountsForm,
},
{
root: '#js-google-cloud',
component: App,
},
];
export default () => {
const root = document.querySelector('#js-google-cloud');
const props = JSON.parse(root.getAttribute('data'));
return new Vue({ el: root, render: elementRenderer(App, props) });
for (let i = 0; i < rootComponentMap.length; i += 1) {
const { root, component } = rootComponentMap[i];
const element = document.querySelector(root);
if (element) {
const props = JSON.parse(element.getAttribute('data'));
return new Vue({ el: root, render: elementRenderer(component, props) });
}
}
throw new Error(__('Unknown root'));
};
......@@ -9710,6 +9710,9 @@ msgstr ""
msgid "Create %{workspace} label"
msgstr ""
msgid "Create Google Cloud project"
msgstr ""
msgid "Create New Directory"
msgstr ""
......@@ -15276,6 +15279,9 @@ msgstr ""
msgid "Generate site and private keys at"
msgstr ""
msgid "Generated service account is linked to the selected environment"
msgstr ""
msgid "Generic"
msgstr ""
......@@ -15825,6 +15831,9 @@ msgstr ""
msgid "GitLab account request rejected"
msgstr ""
msgid "GitLab and Google Cloud configuration seems to be incomplete. This probably can be fixed by your GitLab administration team. You may share these logs with them:"
msgstr ""
msgid "GitLab commit"
msgstr ""
......@@ -16215,6 +16224,15 @@ msgstr ""
msgid "Google Cloud authorizations required"
msgstr ""
msgid "Google Cloud project"
msgstr ""
msgid "Google Cloud project misconfigured"
msgstr ""
msgid "Google Cloud project required"
msgstr ""
msgid "Google authentication is not %{link_start}properly configured%{link_end}. Ask your GitLab administrator if you want to use this service."
msgstr ""
......@@ -23265,6 +23283,9 @@ msgstr ""
msgid "New schedule"
msgstr ""
msgid "New service account is generated for the selected Google Cloud project"
msgstr ""
msgid "New snippet"
msgstr ""
......@@ -37091,6 +37112,9 @@ msgstr ""
msgid "Unknown response text"
msgstr ""
msgid "Unknown root"
msgstr ""
msgid "Unknown user"
msgstr ""
......@@ -39736,6 +39760,9 @@ msgstr ""
msgid "You could not create a new trigger."
msgstr ""
msgid "You do not have any Google Cloud projects. Please create a Google Cloud project and then reload this page."
msgstr ""
msgid "You do not have any subscriptions yet"
msgstr ""
......
import { shallowMount } from '@vue/test-utils';
import { GlAlert } from '@gitlab/ui';
import GcpError from '~/google_cloud/components/errors/gcp_error.vue';
describe('GcpError component', () => {
let wrapper;
const findAlert = () => wrapper.findComponent(GlAlert);
const findBlockquote = () => wrapper.find('blockquote');
const propsData = { error: 'IAM and CloudResourceManager API disabled' };
beforeEach(() => {
wrapper = shallowMount(GcpError, { propsData });
});
afterEach(() => {
wrapper.destroy();
});
it('contains alert', () => {
expect(findAlert().exists()).toBe(true);
});
it('contains relevant text', () => {
const alertText = findAlert().text();
expect(findAlert().props('title')).toBe(GcpError.i18n.title);
expect(alertText).toContain(GcpError.i18n.description);
});
it('contains error stacktrace', () => {
expect(findBlockquote().text()).toBe(propsData.error);
});
});
import { mount } from '@vue/test-utils';
import { GlAlert, GlButton } from '@gitlab/ui';
import NoGcpProjects from '~/google_cloud/components/errors/no_gcp_projects.vue';
describe('NoGcpProjects component', () => {
let wrapper;
const findAlert = () => wrapper.findComponent(GlAlert);
const findButton = () => wrapper.findComponent(GlButton);
beforeEach(() => {
wrapper = mount(NoGcpProjects);
});
afterEach(() => {
wrapper.destroy();
});
it('contains alert', () => {
expect(findAlert().exists()).toBe(true);
});
it('contains relevant text', () => {
expect(findAlert().props('title')).toBe(NoGcpProjects.i18n.title);
expect(findAlert().text()).toContain(NoGcpProjects.i18n.description);
});
it('contains create gcp project button', () => {
const button = findButton();
expect(button.text()).toBe(NoGcpProjects.i18n.createLabel);
expect(button.attributes('href')).toBe('https://console.cloud.google.com/projectcreate');
});
});
import { shallowMount } from '@vue/test-utils';
import { GlTab, GlTabs } from '@gitlab/ui';
import App from '~/google_cloud/components/app.vue';
import App from '~/google_cloud/components/screens/app.vue';
import IncubationBanner from '~/google_cloud/components/incubation_banner.vue';
import ServiceAccounts from '~/google_cloud/components/service_accounts.vue';
import ServiceAccountsList from '~/google_cloud/components/service_accounts_list.vue';
describe('google_cloud App component', () => {
let wrapper;
......@@ -13,7 +13,7 @@ describe('google_cloud App component', () => {
const findConfigurationTab = () => findTabItems().at(0);
const findDeploymentTab = () => findTabItems().at(1);
const findServicesTab = () => findTabItems().at(2);
const findServiceAccounts = () => findConfigurationTab().findComponent(ServiceAccounts);
const findServiceAccountsList = () => findConfigurationTab().findComponent(ServiceAccountsList);
beforeEach(() => {
const propsData = {
......@@ -47,7 +47,7 @@ describe('google_cloud App component', () => {
});
it('should contain service accounts component', () => {
expect(findServiceAccounts().exists()).toBe(true);
expect(findServiceAccountsList().exists()).toBe(true);
});
});
......
import { shallowMount } from '@vue/test-utils';
import { GlButton, GlFormGroup, GlFormSelect } from '@gitlab/ui';
import IncubationBanner from '~/google_cloud/components/incubation_banner.vue';
import ServiceAccountsForm from '~/google_cloud/components/screens/service_accounts_form.vue';
describe('ServiceAccountsForm component', () => {
let wrapper;
const findIncubationBanner = () => wrapper.findComponent(IncubationBanner);
const findHeader = () => wrapper.find('header');
const findAllFormGroups = () => wrapper.findAllComponents(GlFormGroup);
const findAllFormSelects = () => wrapper.findAllComponents(GlFormSelect);
const findAllButtons = () => wrapper.findAllComponents(GlButton);
const propsData = { gcpProjects: [], environments: [], cancelPath: '#cancel-url' };
beforeEach(() => {
wrapper = shallowMount(ServiceAccountsForm, { propsData });
});
afterEach(() => {
wrapper.destroy();
});
it('contains incubation banner', () => {
expect(findIncubationBanner().exists()).toBe(true);
});
it('contains header', () => {
expect(findHeader().exists()).toBe(true);
});
it('contains GCP project form group', () => {
const formGroup = findAllFormGroups().at(0);
expect(formGroup.exists()).toBe(true);
});
it('contains GCP project dropdown', () => {
const select = findAllFormSelects().at(0);
expect(select.exists()).toBe(true);
});
it('contains Environments form group', () => {
const formGorup = findAllFormGroups().at(1);
expect(formGorup.exists()).toBe(true);
});
it('contains Environments dropdown', () => {
const select = findAllFormSelects().at(1);
expect(select.exists()).toBe(true);
});
it('contains Submit button', () => {
const button = findAllButtons().at(0);
expect(button.exists()).toBe(true);
expect(button.text()).toBe(ServiceAccountsForm.i18n.submitLabel);
});
it('contains Cancel button', () => {
const button = findAllButtons().at(1);
expect(button.exists()).toBe(true);
expect(button.text()).toBe(ServiceAccountsForm.i18n.cancelLabel);
expect(button.attributes('href')).toBe('#cancel-url');
});
});
import { mount } from '@vue/test-utils';
import { GlButton, GlEmptyState, GlTable } from '@gitlab/ui';
import ServiceAccounts from '~/google_cloud/components/service_accounts.vue';
import ServiceAccountsList from '~/google_cloud/components/service_accounts_list.vue';
describe('ServiceAccounts component', () => {
describe('when the project does not have any service accounts', () => {
......@@ -15,7 +15,7 @@ describe('ServiceAccounts component', () => {
createUrl: '#create-url',
emptyIllustrationUrl: '#empty-illustration-url',
};
wrapper = mount(ServiceAccounts, { propsData });
wrapper = mount(ServiceAccountsList, { propsData });
});
afterEach(() => {
......@@ -48,7 +48,7 @@ describe('ServiceAccounts component', () => {
createUrl: '#create-url',
emptyIllustrationUrl: '#empty-illustration-url',
};
wrapper = mount(ServiceAccounts, { propsData });
wrapper = mount(ServiceAccountsList, { propsData });
});
it('shows the title', () => {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment