Create download modal following setup completion

This commit is contained in:
Sam Chow 2018-06-27 13:49:54 -04:00
parent aa93d698b2
commit 2d0a599aab
12 changed files with 142 additions and 52 deletions

View file

@ -65,7 +65,6 @@ class SuperUserConfig(ApiResource):
""" Updates the config override file. """ """ Updates the config override file. """
# Note: This method is called to set the database configuration before super users exists, # Note: This method is called to set the database configuration before super users exists,
# so we also allow it to be called if there is no valid registry configuration setup. # so we also allow it to be called if there is no valid registry configuration setup.
if not config_provider.config_exists():
config_object = request.get_json()['config'] config_object = request.get_json()['config']
hostname = request.get_json()['hostname'] hostname = request.get_json()['hostname']
@ -101,9 +100,6 @@ class SuperUserConfig(ApiResource):
'config': config_object 'config': config_object
} }
abort(403)
@resource('/v1/superuser/registrystatus') @resource('/v1/superuser/registrystatus')
class SuperUserRegistryStatus(ApiResource): class SuperUserRegistryStatus(ApiResource):

View file

@ -37,15 +37,14 @@ class TarConfigLoader(ApiResource):
if os.path.isfile('quay-config.tar.gz'): if os.path.isfile('quay-config.tar.gz'):
os.remove('quay-config.tar.gz') os.remove('quay-config.tar.gz')
tar = tarfile.open('quay-config.tar.gz', mode="w:gz") tar = tarfile.open('quay-config.tar.gz', mode="w|gz")
for name in os.listdir(config_path): for name in os.listdir(config_path):
tar.add(os.path.join(config_path, name), filter=tarinfo_filter) tar.add(os.path.join(config_path, name), filter=tarinfo_filter)
tar.close() tar.close()
return send_file('quay-config.tar.gz', mimetype='application/gzip', return send_file('quay-config.tar.gz', mimetype='application/gzip')
as_attachment=True, attachment_filename='quay-config.tar.gz')
@nickname('scUploadTarballConfig') @nickname('scUploadTarballConfig')
def put(self): def put(self):

View file

@ -22,5 +22,6 @@
</div><!-- /.modal-dialog --> </div><!-- /.modal-dialog -->
</div> </div>
</div> </div>
<div ng-if="$ctrl.state === 'setup'" class="setup"></div> <div ng-if="$ctrl.state === 'setup'" class="setup" setup-completed="$ctrl.setupCompleted()"></div>
<load-config ng-if="$ctrl.state === 'load'" config-loaded="$ctrl.configLoaded()"></load-config> <load-config ng-if="$ctrl.state === 'load'" config-loaded="$ctrl.configLoaded()"></load-config>
<download-tarball-modal ng-if="$ctrl.state === 'download'" loaded-config="$ctrl.loadedConfig"></download-tarball-modal>

View file

@ -1,4 +1,4 @@
import { Input, Component, Inject } from 'ng-metadata/core'; import { Component } from 'ng-metadata/core';
const templateUrl = require('./config-setup-app.component.html'); const templateUrl = require('./config-setup-app.component.html');
/** /**
@ -9,7 +9,13 @@ const templateUrl = require('./config-setup-app.component.html');
templateUrl: templateUrl, templateUrl: templateUrl,
}) })
export class ConfigSetupAppComponent { export class ConfigSetupAppComponent {
private state: 'choice' | 'setup' | 'load'; private state
: 'choice'
| 'setup'
| 'load'
| 'download';
private loadedConfig = false;
constructor() { constructor() {
this.state = 'choice'; this.state = 'choice';
@ -21,9 +27,14 @@ export class ConfigSetupAppComponent {
private chooseLoad(): void { private chooseLoad(): void {
this.state = 'load'; this.state = 'load';
this.loadedConfig = true;
} }
private configLoaded(): void { private configLoaded(): void {
this.state = 'setup'; this.state = 'setup';
} }
private setupCompleted(): void {
this.state = 'download';
}
} }

View file

@ -0,0 +1,42 @@
<div>
<div class="co-dialog modal fade initial-setup-modal in" id="setupModal" style="display: block;">
<div class="modal-backdrop fade in" style="height: 1000px;"></div>
<div class="modal-dialog fade in">
<div class="modal-content">
<!-- Header -->
<div class="modal-header">
<h4 class="modal-title"><span>Download Configuration</span></h4>
</div>
<!-- Body -->
<div class="modal-body">
<div ng-if="$ctrl.loadedConfig">
Please download your updated configuration. To deploy these changes to your Quay Enterprise instances, please
<a target="_blank" href="https://coreos.com/quay-enterprise/docs/latest/initial-setup.html">
see the docs.
</a>
<div class="modal__warning-box">
<i class="fas fa-exclamation-triangle" style="margin-right: 10px;"></i><strong>Warning:</strong>
Your configuration and certificates are kept <i>unencrypted</i>. Please keep this file secure.
</div>
</div>
<div ng-if="!$ctrl.loadedConfig">
Please download your new configuration. For more information, and next steps, please
<a target="_blank" href="https://coreos.com/quay-enterprise/docs/latest/initial-setup.html">
see the docs.
</a>
<div class="modal__warning-box">
<i class="fas fa-exclamation-triangle" style="margin-right: 10px;"></i><strong>Warning: </strong>
Your configuration and certificates are kept <i>unencrypted</i>. Please keep this file secure.
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-primary"
ng-click="$ctrl.downloadTarball()">
<i class="fa fa-download" style="margin-right: 10px;"></i>Download Configuration
</button>
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div>
</div>

View file

@ -0,0 +1,34 @@
import { Input, Component, Inject } from 'ng-metadata/core';
const templateUrl = require('./download-tarball-modal.component.html');
const styleUrl = require('./download-tarball-modal.css');
declare const FileSaver: any;
/**
* Initial Screen and Choice in the Config App
*/
@Component({
selector: 'download-tarball-modal',
templateUrl: templateUrl,
styleUrls: [ styleUrl ],
})
export class DownloadTarballModalComponent {
@Input('<') public loadedConfig;
constructor(@Inject('ApiService') private ApiService) {
}
private downloadTarball() {
const errorDisplay: Function = this.ApiService.errorDisplay(
'Could not save configuration. Please report this error.'
);
// We need to set the response type to 'blob', to ensure it's never encoded as a string
// (string encoded binary data can be difficult to transform with js)
// and to make it easier to save (FileSaver expects a blob)
this.ApiService.scGetConfigTarball(null, null, null, null, true).then(function(resp) {
FileSaver.saveAs(resp, 'quay-config.tar.gz');
}, errorDisplay);
}
}

View file

@ -0,0 +1,6 @@
.modal__warning-box {
background-color: #ddd;
padding: 15px;
border-radius: 5px;
margin-top: 15px;
}

View file

@ -2,6 +2,7 @@ import { NgModule } from 'ng-metadata/core';
import * as restangular from 'restangular'; import * as restangular from 'restangular';
import { ConfigSetupAppComponent } from './components/config-setup-app/config-setup-app.component'; import { ConfigSetupAppComponent } from './components/config-setup-app/config-setup-app.component';
import { DownloadTarballModalComponent } from './components/download-tarball-modal/download-tarball-modal.component';
import { LoadConfigComponent } from './components/load-config/load-config.component'; import { LoadConfigComponent } from './components/load-config/load-config.component';
const quayDependencies: string[] = [ const quayDependencies: string[] = [
@ -42,6 +43,7 @@ function provideConfig($provide: ng.auto.IProvideService,
imports: [ DependencyConfig ], imports: [ DependencyConfig ],
declarations: [ declarations: [
ConfigSetupAppComponent, ConfigSetupAppComponent,
DownloadTarballModalComponent,
LoadConfigComponent, LoadConfigComponent,
], ],
providers: [] providers: []

View file

@ -1,7 +1,6 @@
<div class="config-setup-tool-element"> <div class="config-setup-tool-element">
<div class="cor-loader" ng-if="!config"></div> <div class="cor-loader" ng-if="!config"></div>
<div ng-show="true"> <div ng-show="true">
<!--<div ng-show="config && config['SUPER_USERS']">-->
<form id="configform" name="configform"> <form id="configform" name="configform">
<!-- Custom SSL certificates --> <!-- Custom SSL certificates -->
@ -1630,9 +1629,9 @@
</span> </span>
<button class="btn btn-primary" <button class="btn btn-primary"
ng-click="generateConfigTarball()" ng-click="saveConfiguration()"
ng-disabled="savingConfiguration"> ng-disabled="savingConfiguration">
<i class="fa fa-upload" style="margin-right: 10px;"></i>Generate Configuration Next
</button> </button>
</div> </div>

View file

@ -27,7 +27,8 @@ angular.module("quay-config")
restrict: 'C', restrict: 'C',
scope: { scope: {
'isActive': '=isActive', 'isActive': '=isActive',
'configurationSaved': '&configurationSaved' 'configurationSaved': '&configurationSaved',
'setupCompleted': '&setupCompleted',
}, },
controller: function($rootScope, $scope, $element, $timeout, ApiService) { controller: function($rootScope, $scope, $element, $timeout, ApiService) {
var authPassword = null; var authPassword = null;
@ -413,7 +414,7 @@ angular.module("quay-config")
} }
}; };
$scope.generateConfigTarball = function() { $scope.saveConfiguration = function() {
$scope.savingConfiguration = true; $scope.savingConfiguration = true;
// Make sure to note that fully verified setup is completed. We use this as a signal // Make sure to note that fully verified setup is completed. We use this as a signal
@ -432,20 +433,16 @@ angular.module("quay-config")
authPassword = null; authPassword = null;
}); });
// We need to set the response type to 'blob', to ensure it's never encoded as a string ApiService.scUpdateConfig(data).then(function(resp) {
// (string encoded binary data can be difficult to transform with js)
// and to make it easier to save (FileSaver expects a blob)
ApiService.scGetConfigTarball(null, null, null, null, true).then(function(resp) {
authPassword = null; authPassword = null;
FileSaver.saveAs(resp, 'quay-config.tar.gz');
$scope.savingConfiguration = false; $scope.savingConfiguration = false;
$scope.mapped.$hasChanges = false; $scope.mapped.$hasChanges = false;
$('#validateAndSaveModal').modal('hide'); $('#validateAndSaveModal').modal('hide');
$scope.configurationSaved({'config': $scope.config}); // $scope.configurationSaved({'config': $scope.config});
$scope.setupCompleted();
}, errorDisplay); }, errorDisplay);
}; };

View file

@ -15,7 +15,8 @@ const templateUrl = require('./setup.html');
restrict: 'C', restrict: 'C',
scope: { scope: {
'isActive': '=isActive', 'isActive': '=isActive',
'configurationSaved': '&configurationSaved' 'configurationSaved': '&configurationSaved',
'setupCompleted': '&setupCompleted',
}, },
controller: SetupCtrl, controller: SetupCtrl,
}; };

View file

@ -25,7 +25,9 @@
</div> </div>
<div class="config-setup-tool" is-active="isStep(currentStep, States.CONFIG)" <div class="config-setup-tool" is-active="isStep(currentStep, States.CONFIG)"
configuration-saved="configurationSaved(config)"></divconfig-setup-tool> configuration-saved="configurationSaved(config)"
setup-completed="setupCompleted()"
></div>
</div> </div>
</div> </div>
</div> </div>