Commit 9fb1df8f authored by Mike Greiling's avatar Mike Greiling Committed by Fatih Acet

Hide cluster details until cluster is created

Only display the details of the cluster page when the cluster
exists. If it is in "creating" state, show a message and a spinner
parent 57e00e19
...@@ -48,6 +48,9 @@ export default class Clusters { ...@@ -48,6 +48,9 @@ export default class Clusters {
} = document.querySelector('.js-edit-cluster-form').dataset; } = document.querySelector('.js-edit-cluster-form').dataset;
this.clusterId = clusterId; this.clusterId = clusterId;
this.clusterNewlyCreatedKey = `cluster_${this.clusterId}_newly_created`;
this.clusterBannerDismissedKey = `cluster_${this.clusterId}_banner_dismissed`;
this.store = new ClustersStore(); this.store = new ClustersStore();
this.store.setHelpPaths(helpPath, ingressHelpPath, ingressDnsHelpPath); this.store.setHelpPaths(helpPath, ingressHelpPath, ingressDnsHelpPath);
this.store.setManagePrometheusPath(managePrometheusPath); this.store.setManagePrometheusPath(managePrometheusPath);
...@@ -81,18 +84,19 @@ export default class Clusters { ...@@ -81,18 +84,19 @@ export default class Clusters {
this.showTokenButton = document.querySelector('.js-show-cluster-token'); this.showTokenButton = document.querySelector('.js-show-cluster-token');
this.tokenField = document.querySelector('.js-cluster-token'); this.tokenField = document.querySelector('.js-cluster-token');
this.ingressDomainHelpText = document.querySelector('.js-ingress-domain-help-text'); this.ingressDomainHelpText = document.querySelector('.js-ingress-domain-help-text');
this.ingressDomainSnippet = this.ingressDomainHelpText.querySelector( this.ingressDomainSnippet =
'.js-ingress-domain-snippet', this.ingressDomainHelpText &&
); this.ingressDomainHelpText.querySelector('.js-ingress-domain-snippet');
Clusters.initDismissableCallout(); Clusters.initDismissableCallout();
initSettingsPanels(); initSettingsPanels();
setupToggleButtons(document.querySelector('.js-cluster-enable-toggle-area')); const toggleButtonsContainer = document.querySelector('.js-cluster-enable-toggle-area');
if (toggleButtonsContainer) {
setupToggleButtons(toggleButtonsContainer);
}
this.initApplications(clusterType); this.initApplications(clusterType);
if (this.store.state.status !== 'created') { this.updateContainer(null, this.store.state.status, this.store.state.statusReason);
this.updateContainer(null, this.store.state.status, this.store.state.statusReason);
}
this.addListeners(); this.addListeners();
if (statusPath) { if (statusPath) {
...@@ -247,35 +251,56 @@ export default class Clusters { ...@@ -247,35 +251,56 @@ export default class Clusters {
setBannerDismissedState(status, isDismissed) { setBannerDismissedState(status, isDismissed) {
if (AccessorUtilities.isLocalStorageAccessSafe()) { if (AccessorUtilities.isLocalStorageAccessSafe()) {
window.localStorage.setItem( window.localStorage.setItem(this.clusterBannerDismissedKey, `${status}_${isDismissed}`);
`cluster_${this.clusterId}_banner_dismissed`,
`${status}_${isDismissed}`,
);
} }
} }
isBannerDismissed(status) { isBannerDismissed(status) {
let bannerState; let bannerState;
if (AccessorUtilities.isLocalStorageAccessSafe()) { if (AccessorUtilities.isLocalStorageAccessSafe()) {
bannerState = window.localStorage.getItem(`cluster_${this.clusterId}_banner_dismissed`); bannerState = window.localStorage.getItem(this.clusterBannerDismissedKey);
} }
return bannerState === `${status}_true`; return bannerState === `${status}_true`;
} }
updateContainer(prevStatus, status, error) { setClusterNewlyCreated(state) {
this.hideAll(); if (AccessorUtilities.isLocalStorageAccessSafe()) {
window.localStorage.setItem(this.clusterNewlyCreatedKey, Boolean(state));
}
}
isClusterNewlyCreated() {
// once this is true, it will always be true for a given page load
if (!this.isNewlyCreated) {
let newlyCreated;
if (AccessorUtilities.isLocalStorageAccessSafe()) {
newlyCreated = window.localStorage.getItem(this.clusterNewlyCreatedKey);
}
this.isNewlyCreated = newlyCreated === 'true';
}
return this.isNewlyCreated;
}
if (this.isBannerDismissed(status)) { updateContainer(prevStatus, status, error) {
if (status !== 'created' && this.isBannerDismissed(status)) {
return; return;
} }
this.setBannerDismissedState(status, false); this.setBannerDismissedState(status, false);
// We poll all the time but only want the `created` banner to show when newly created if (prevStatus !== status) {
if (this.store.state.status !== 'created' || prevStatus !== this.store.state.status) { this.hideAll();
switch (status) { switch (status) {
case 'created': case 'created':
this.successContainer.classList.remove('hidden'); if (this.isClusterNewlyCreated()) {
this.setClusterNewlyCreated(false);
this.successContainer.classList.remove('hidden');
} else if (prevStatus) {
this.setClusterNewlyCreated(true);
window.location.reload();
}
break; break;
case 'errored': case 'errored':
this.errorContainer.classList.remove('hidden'); this.errorContainer.classList.remove('hidden');
...@@ -292,7 +317,6 @@ export default class Clusters { ...@@ -292,7 +317,6 @@ export default class Clusters {
this.creatingContainer.classList.remove('hidden'); this.creatingContainer.classList.remove('hidden');
break; break;
default: default:
this.hideAll();
} }
} }
} }
......
...@@ -28,8 +28,10 @@ const setState = glManagedCheckbox => { ...@@ -28,8 +28,10 @@ const setState = glManagedCheckbox => {
const initGkeNamespace = () => { const initGkeNamespace = () => {
const glManagedCheckbox = document.querySelector('.js-gl-managed'); const glManagedCheckbox = document.querySelector('.js-gl-managed');
setState(glManagedCheckbox); // this is needed in order to set the initial state if (glManagedCheckbox) {
glManagedCheckbox.addEventListener('change', () => setState(glManagedCheckbox)); setState(glManagedCheckbox); // this is needed in order to set the initial state
glManagedCheckbox.addEventListener('change', () => setState(glManagedCheckbox));
}
}; };
export default initGkeNamespace; export default initGkeNamespace;
...@@ -3,7 +3,8 @@ ...@@ -3,7 +3,8 @@
%p.js-error-reason %p.js-error-reason
.hidden.js-cluster-creating.bs-callout.bs-callout-info{ role: 'alert' } .hidden.js-cluster-creating.bs-callout.bs-callout-info{ role: 'alert' }
= s_('ClusterIntegration|Kubernetes cluster is being created on Google Kubernetes Engine...') %span.spinner.spinner-dark.spinner-sm{ 'aria-label': 'Loading' }
%span.prepend-left-4= s_('ClusterIntegration|Kubernetes cluster is being created on Google Kubernetes Engine...')
.hidden.row.js-cluster-api-unreachable.bs-callout.bs-callout-warning{ role: 'alert' } .hidden.row.js-cluster-api-unreachable.bs-callout.bs-callout-warning{ role: 'alert' }
.col-11 .col-11
...@@ -18,4 +19,4 @@ ...@@ -18,4 +19,4 @@
%button.js-close-banner.close.cluster-application-banner-close.h-100.m-0= "×" %button.js-close-banner.close.cluster-application-banner-close.h-100.m-0= "×"
.hidden.js-cluster-success.bs-callout.bs-callout-success{ role: 'alert' } .hidden.js-cluster-success.bs-callout.bs-callout-success{ role: 'alert' }
= s_("ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine. Refresh the page to see Kubernetes cluster's details") = s_("ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine.")
...@@ -33,26 +33,29 @@ ...@@ -33,26 +33,29 @@
%section#cluster-integration %section#cluster-integration
%h4= @cluster.name %h4= @cluster.name
= render 'banner' = render 'banner'
= render 'form'
- unless @cluster.status_name.in? %i/scheduled creating/
= render_if_exists 'projects/clusters/prometheus_graphs' = render 'form'
.cluster-applications-table#js-cluster-applications - unless @cluster.status_name.in? %i/scheduled creating/
= render_if_exists 'projects/clusters/prometheus_graphs'
%section.settings#js-cluster-details{ class: ('expanded' if expanded) }
.settings-header .cluster-applications-table#js-cluster-applications
%h4= s_('ClusterIntegration|Kubernetes cluster details')
%button.btn.js-settings-toggle{ type: 'button' } %section.settings#js-cluster-details{ class: ('expanded' if expanded) }
= expanded ? _('Collapse') : _('Expand') .settings-header
%p= s_('ClusterIntegration|See and edit the details for your Kubernetes cluster') %h4= s_('ClusterIntegration|Kubernetes cluster details')
.settings-content %button.btn.js-settings-toggle{ type: 'button' }
= render 'clusters/platforms/kubernetes/form', cluster: @cluster, platform: @cluster.platform_kubernetes, update_cluster_url_path: clusterable.cluster_path(@cluster) = expanded ? _('Collapse') : _('Expand')
%p= s_('ClusterIntegration|See and edit the details for your Kubernetes cluster')
%section.settings.no-animate#js-cluster-advanced-settings{ class: ('expanded' if expanded) } .settings-content
.settings-header = render 'clusters/platforms/kubernetes/form', cluster: @cluster, platform: @cluster.platform_kubernetes, update_cluster_url_path: clusterable.cluster_path(@cluster)
%h4= _('Advanced settings')
%button.btn.js-settings-toggle{ type: 'button' } %section.settings.no-animate#js-cluster-advanced-settings{ class: ('expanded' if expanded) }
= expanded ? _('Collapse') : _('Expand') .settings-header
%p= s_("ClusterIntegration|Advanced options on this Kubernetes cluster's integration") %h4= _('Advanced settings')
.settings-content#advanced-settings-section %button.btn.js-settings-toggle{ type: 'button' }
= render 'advanced_settings' = expanded ? _('Collapse') : _('Expand')
%p= s_("ClusterIntegration|Advanced options on this Kubernetes cluster's integration")
.settings-content#advanced-settings-section
= render 'advanced_settings'
---
title: Update cluster page automatically when cluster is created
merge_request: 27189
author:
type: changed
...@@ -2647,7 +2647,7 @@ msgstr "" ...@@ -2647,7 +2647,7 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes cluster name" msgid "ClusterIntegration|Kubernetes cluster name"
msgstr "" msgstr ""
msgid "ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine. Refresh the page to see Kubernetes cluster's details" msgid "ClusterIntegration|Kubernetes cluster was successfully created on Google Kubernetes Engine."
msgstr "" msgstr ""
msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way." msgid "ClusterIntegration|Kubernetes clusters allow you to use review apps, deploy your applications, run your pipelines, and much more in an easy way."
......
...@@ -22,9 +22,8 @@ describe 'Clusters Applications', :js do ...@@ -22,9 +22,8 @@ describe 'Clusters Applications', :js do
let(:cluster) { create(:cluster, :providing_by_gcp, projects: [project]) } let(:cluster) { create(:cluster, :providing_by_gcp, projects: [project]) }
it 'user is unable to install applications' do it 'user is unable to install applications' do
page.within('.js-cluster-application-row-helm') do expect(page).not_to have_css('.js-cluster-application-row-helm')
expect(page).to have_css('.js-cluster-application-install-button[disabled]', exact_text: 'Install') expect(page).not_to have_css('.js-cluster-application-install-button')
end
end end
end end
......
...@@ -147,47 +147,80 @@ describe('Clusters', () => { ...@@ -147,47 +147,80 @@ describe('Clusters', () => {
}); });
describe('updateContainer', () => { describe('updateContainer', () => {
const { location } = window;
beforeEach(() => {
delete window.location;
window.location = {
reload: jest.fn(),
hash: location.hash,
};
});
afterEach(() => {
window.location = location;
});
describe('when creating cluster', () => { describe('when creating cluster', () => {
it('should show the creating container', () => { it('should show the creating container', () => {
cluster.updateContainer(null, 'creating'); cluster.updateContainer(null, 'creating');
expect(cluster.creatingContainer.classList.contains('hidden')).toBeFalsy(); expect(cluster.creatingContainer.classList.contains('hidden')).toBeFalsy();
expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy(); expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy();
expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy(); expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy();
expect(window.location.reload).not.toHaveBeenCalled();
}); });
it('should continue to show `creating` banner with subsequent updates of the same status', () => { it('should continue to show `creating` banner with subsequent updates of the same status', () => {
cluster.updateContainer(null, 'creating');
cluster.updateContainer('creating', 'creating'); cluster.updateContainer('creating', 'creating');
expect(cluster.creatingContainer.classList.contains('hidden')).toBeFalsy(); expect(cluster.creatingContainer.classList.contains('hidden')).toBeFalsy();
expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy(); expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy();
expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy(); expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy();
expect(window.location.reload).not.toHaveBeenCalled();
}); });
}); });
describe('when cluster is created', () => { describe('when cluster is created', () => {
it('should show the success container and fresh the page', () => { it('should hide the "creating" banner and refresh the page', () => {
cluster.updateContainer(null, 'created'); jest.spyOn(cluster, 'setClusterNewlyCreated');
cluster.updateContainer(null, 'creating');
cluster.updateContainer('creating', 'created');
expect(cluster.creatingContainer.classList.contains('hidden')).toBeTruthy(); expect(cluster.creatingContainer.classList.contains('hidden')).toBeTruthy();
expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy();
expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy();
expect(window.location.reload).toHaveBeenCalled();
expect(cluster.setClusterNewlyCreated).toHaveBeenCalledWith(true);
});
expect(cluster.successContainer.classList.contains('hidden')).toBeFalsy(); it('when the page is refreshed, it should show the "success" banner', () => {
jest.spyOn(cluster, 'setClusterNewlyCreated');
jest.spyOn(cluster, 'isClusterNewlyCreated').mockReturnValue(true);
cluster.updateContainer(null, 'created');
cluster.updateContainer('created', 'created');
expect(cluster.creatingContainer.classList.contains('hidden')).toBeTruthy();
expect(cluster.successContainer.classList.contains('hidden')).toBeFalsy();
expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy(); expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy();
expect(window.location.reload).not.toHaveBeenCalled();
expect(cluster.setClusterNewlyCreated).toHaveBeenCalledWith(false);
}); });
it('should not show a banner when status is already `created`', () => { it('should not show a banner when status is already `created`', () => {
jest.spyOn(cluster, 'setClusterNewlyCreated');
jest.spyOn(cluster, 'isClusterNewlyCreated').mockReturnValue(false);
cluster.updateContainer(null, 'created');
cluster.updateContainer('created', 'created'); cluster.updateContainer('created', 'created');
expect(cluster.creatingContainer.classList.contains('hidden')).toBeTruthy(); expect(cluster.creatingContainer.classList.contains('hidden')).toBeTruthy();
expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy(); expect(cluster.successContainer.classList.contains('hidden')).toBeTruthy();
expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy(); expect(cluster.errorContainer.classList.contains('hidden')).toBeTruthy();
expect(window.location.reload).not.toHaveBeenCalled();
expect(cluster.setClusterNewlyCreated).not.toHaveBeenCalled();
}); });
}); });
......
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