Skip to content

Commit 0064499

Browse files
authored
Download code view content (#188)
* Allow saving install script from WLS Operator page * Allow saving scripts and resource files for VZ install, component, and application pages * Allow saving scripts and resource files for operator domain, image, and ingress pages
1 parent f7de948 commit 0064499

19 files changed

+285
-9
lines changed

electron/app/js/ipcRendererPreload.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ contextBridge.exposeInMainWorld(
3131
send: (channel, ...args) => {
3232
const validChannels = [
3333
'close-window',
34+
'download-file',
3435
'new-project',
3536
'open-project',
3637
'window-app-quit',

electron/app/js/project.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const {getCredentialPassphrase} = require('./promptUtils');
88
const {copyFile, mkdir, readFile, writeFile} = require('fs/promises');
99
const path = require('path');
1010
const uuid = require('uuid');
11+
const { EOL } = require('os');
1112

1213
const model = require('./model');
1314
const modelProperties = require('./modelProperties');
@@ -972,6 +973,32 @@ function getProjectFileName(dialogReturnedFileName) {
972973
return result;
973974
}
974975

976+
function downloadFile(targetWindow, lines, fileType, format, formatName) {
977+
const title = i18n.t('dialog-saveTitle', {type: fileType});
978+
const filterName = i18n.t('dialog-saveFilterLabel', {type: formatName});
979+
980+
dialog.showSaveDialog(targetWindow, {
981+
title: title,
982+
message: title,
983+
filters: [
984+
{name: filterName, extensions: [format]}
985+
],
986+
properties: [
987+
'createDirectory',
988+
'showOverwriteConfirmation'
989+
]
990+
}).then(saveResponse => {
991+
if (saveResponse.filePath) {
992+
const contents = lines.join(EOL);
993+
writeFile(saveResponse.filePath, contents, { encoding: 'utf8' })
994+
.catch(err => {
995+
dialog.showErrorBox(title,
996+
i18n.t('dialog-saveFileErrorMessage', { file: saveResponse.filePath, error: err }));
997+
});
998+
}
999+
});
1000+
}
1001+
9751002
module.exports = {
9761003
chooseArchiveFile,
9771004
chooseModelFile,
@@ -980,6 +1007,7 @@ module.exports = {
9801007
closeProject,
9811008
confirmProjectFile,
9821009
createNewProject,
1010+
downloadFile,
9831011
getModelFileContent,
9841012
getWindowForProject,
9851013
exportArchiveFile,

electron/app/locales/en/electron.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@
159159
"dialog-createNewProjectTitle": "Create WebLogic Kubernetes Toolkit Project",
160160
"dialog-projectSaveFileLocationNotWritableTitle": "Project Directory Not Writable",
161161
"dialog-projectSaveFileLocationNotWritableError": "The {{projectFileDirectory}} directory chosen to write the new project file is not writable by the current process.",
162+
"dialog-saveTitle": "Save {{type}}",
163+
"dialog-saveFilterLabel": "{{type}} Files",
164+
"dialog-saveFileErrorMessage": "Unable to save {{file}}: {{error}}",
162165

163166
"dialog-openProjectWindowPrompt": "Choose the window where the project should be opened.",
164167
"dialog-chooseDomainHome": "Select the Domain Home directory to use",

electron/app/locales/en/webui.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
"script-sh-label": "sh Script",
3434
"script-ps1-label": "Powershell Script",
3535
"script-cmd-label": "Windows CMD Script",
36+
"script-button-download": "Download",
37+
"script-file-type-label": "{{type}} {{subType}}",
38+
"script-resource-file-format": "Resource",
3639

3740
"kubectl-form-name": "Kubernetes Client Configuration",
3841
"kubectl-title": "Configure the Kubernetes Client",
@@ -229,6 +232,7 @@
229232
"image-code-primary-image-script-no-content": "Create New Primary Image is turned off so no content to show.",
230233
"image-code-auxiliary-image-script-no-content": "Create New Auxiliary Image is turned off so no content to show.",
231234
"image-code-not-creating-images-no-content": "This project is not configured to create any images so no content to show.",
235+
"image-code-script-title": "{{type}} Script",
232236

233237
"image-design-form-name": "Image",
234238
"image-design-form-primary-tab-name": "Primary Image",

electron/app/main.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,11 @@ class Main {
287287
await currentWindow.close();
288288
});
289289

290+
ipcMain.on('download-file', (event, lines, fileType, fileFormat, fileFormatName) => {
291+
const window = event.sender.getOwnerBrowserWindow();
292+
return project.downloadFile(window, lines, fileType, fileFormat, fileFormatName);
293+
});
294+
290295
// eslint-disable-next-line no-unused-vars
291296
ipcMain.on('skip-quickstart-at-startup', async (event) => {
292297
userSettings.setSkipQuickstartAtStartup(true);

webui/src/js/viewModels/domain-code-view.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,37 @@ function (accUtils, ko, project, K8sDomainScriptGenerator, K8sDomainConfigMapGen
115115
};
116116

117117
this.renderScript(this.selectedSubview());
118+
119+
this.downloadInstaller = () => {
120+
const format = this.shellScriptType();
121+
const generator = new K8sDomainScriptGenerator(format);
122+
const lines = generator.generate();
123+
const fileType = i18n.t('script-file-type-label', {
124+
type: i18n.t('nav-domain'),
125+
subType: i18n.t('domain-code-script-title')
126+
});
127+
const formatLabel = this.shellLabelMapper(format + '-label');
128+
129+
window.api.ipc.send('download-file', lines, fileType, format, formatLabel);
130+
};
131+
132+
this.downloadComponentResource = () => {
133+
const generator = this.getDomainResourceGenerator();
134+
const lines = generator.generate();
135+
const fileType = i18n.t('domain-code-domain-resource-title');
136+
const formatLabel = this.shellLabelMapper('resource-file-format');
137+
138+
window.api.ipc.send('download-file', lines, fileType, 'yaml', formatLabel);
139+
};
140+
141+
this.downloadConfigMap = () => {
142+
const generator = this.k8sConfigMapGenerator;
143+
const lines = generator.generate();
144+
const fileType = i18n.t('domain-code-configmap-resource-title');
145+
const formatLabel = this.shellLabelMapper('resource-file-format');
146+
147+
window.api.ipc.send('download-file', lines, fileType, 'yaml', formatLabel);
148+
};
118149
}
119150

120151
return DomainCodeViewModel;

webui/src/js/viewModels/image-code-view.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,18 @@ function(accUtils, ko, i18n, project, ImageScriptGenerator, ArrayDataProvider) {
116116
};
117117

118118
this.codeText = ko.observable();
119+
120+
this.downloadScript = () => {
121+
const format = this.codeViewScriptLanguage();
122+
const generator = new ImageScriptGenerator(format);
123+
const auxiliary = this.selectedSubview() === 'auxiliaryImageScript';
124+
const lines = auxiliary ? generator.generateAuxiliary() : generator.generatePrimary();
125+
const typeName = this.labelMapper(auxiliary ? 'auxiliary-image-script-tab' : 'primary-image-script-tab');
126+
const fileType = i18n.t('image-code-script-title', {type: typeName});
127+
const formatLabel = this.shellLabelMapper(format + '-label');
128+
129+
window.api.ipc.send('download-file', lines, fileType, format, formatLabel);
130+
};
119131
}
120132

121133
/*

webui/src/js/viewModels/ingress-code-view.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,38 @@ function(accUtils, ko, i18n, project, IngressInstallScriptGenerator, IngressRout
111111
const lines = generator.generate();
112112
this.ingressRoutesYamlText(lines.join('\n'));
113113
};
114+
115+
this.downloadInstaller = () => {
116+
const format = this.shellScriptType();
117+
const generator = new IngressInstallScriptGenerator(format);
118+
const lines = generator.generate();
119+
const fileType = i18n.t('script-file-type-label', {
120+
type: i18n.t('nav-ingress'),
121+
subType: i18n.t('ingress-code-install-script-title')
122+
});
123+
const formatLabel = this.shellLabelMapper(format + '-label');
124+
125+
window.api.ipc.send('download-file', lines, fileType, format, formatLabel);
126+
};
127+
128+
this.downloadAddRoutesScript = () => {
129+
const format = this.shellScriptType();
130+
const generator = new IngressRoutesScriptGenerator(format);
131+
const lines = generator.generate();
132+
const fileType = i18n.t('ingress-code-add-routes-script-title');
133+
const formatLabel = this.shellLabelMapper(format + '-label');
134+
135+
window.api.ipc.send('download-file', lines, fileType, format, formatLabel);
136+
};
137+
138+
this.downloadRoutesResource = () => {
139+
const generator = new IngressResourceGenerator();
140+
const lines = generator.generate();
141+
const fileType = i18n.t('ingress-code-ingress-yaml-title');
142+
const formatLabel = this.shellLabelMapper('resource-file-format');
143+
144+
window.api.ipc.send('download-file', lines, fileType, 'yaml', formatLabel);
145+
};
114146
}
115147

116148
/*

webui/src/js/viewModels/operator-code-view.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,19 @@ function(i18n, accUtils, ko, project, OperatorScriptGenerator, ArrayDataProvider
5050
this.shellScriptType(event.detail.value);
5151
this.updateCodeText(event.detail.value);
5252
};
53+
54+
this.download = () => {
55+
const format = this.shellScriptType();
56+
const generator = new OperatorScriptGenerator(format);
57+
const lines = generator.generate();
58+
const fileType = i18n.t('script-file-type-label', {
59+
type: i18n.t('nav-operator'),
60+
subType: i18n.t('domain-code-script-title')
61+
});
62+
const formatLabel = this.shellLabelMapper(format + '-label');
63+
64+
window.api.ipc.send('download-file', lines, fileType, format, formatLabel);
65+
};
5366
}
5467

5568
/*

webui/src/js/viewModels/vz-application-code-view.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,37 @@ function (accUtils, ko, project, VerrazzanoApplicationScriptGenerator, Verrazzan
107107
};
108108

109109
this.renderScript(this.selectedSubview());
110+
111+
this.downloadDeployer = () => {
112+
const format = this.shellScriptType();
113+
const generator = new VerrazzanoApplicationScriptGenerator(format);
114+
const lines = generator.generate();
115+
const fileType = i18n.t('script-file-type-label', {
116+
type: i18n.t('nav-vz-component'),
117+
subType: i18n.t('vz-install-code-script-title')
118+
});
119+
const formatLabel = this.shellLabelMapper(format + '-label');
120+
121+
window.api.ipc.send('download-file', lines, fileType, format, formatLabel);
122+
};
123+
124+
this.downloadApplicationResource = () => {
125+
const generator = this.vzApplicationResourceGenerator;
126+
const lines = generator.generate();
127+
const fileType = i18n.t('vz-application-code-application-resource-title');
128+
const formatLabel = this.shellLabelMapper('resource-file-format');
129+
130+
window.api.ipc.send('download-file', lines, fileType, 'yaml', formatLabel);
131+
};
132+
133+
this.downloadProjectResource = () => {
134+
const generator = this.vzProjectResourceGenerator;
135+
const lines = generator.generate();
136+
const fileType = i18n.t('vz-application-code-project-resource-title');
137+
const formatLabel = this.shellLabelMapper('resource-file-format');
138+
139+
window.api.ipc.send('download-file', lines, fileType, 'yaml', formatLabel);
140+
};
110141
}
111142

112143
return VerrazzanoApplicationCodeViewModel;

webui/src/js/viewModels/vz-component-code-view.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,37 @@ function (accUtils, ko, project, VerrazzanoComponentScriptGenerator, VerrazzanoC
108108
};
109109

110110
this.renderScript(this.selectedSubview());
111+
112+
this.downloadInstaller = () => {
113+
const format = this.shellScriptType();
114+
const generator = new VerrazzanoComponentScriptGenerator(format);
115+
const lines = generator.generate();
116+
const fileType = i18n.t('script-file-type-label', {
117+
type: i18n.t('nav-vz-component'),
118+
subType: i18n.t('vz-install-code-script-title')
119+
});
120+
const formatLabel = this.shellLabelMapper(format + '-label');
121+
122+
window.api.ipc.send('download-file', lines, fileType, format, formatLabel);
123+
};
124+
125+
this.downloadComponentResource = () => {
126+
const generator = this.vzComponentResourceGenerator;
127+
const lines = generator.generate();
128+
const fileType = i18n.t('vz-component-code-component-resource-title');
129+
const formatLabel = this.shellLabelMapper('resource-file-format');
130+
131+
window.api.ipc.send('download-file', lines, fileType, 'yaml', formatLabel);
132+
};
133+
134+
this.downloadConfigMap = () => {
135+
const generator = this.vzComponentConfigMapGenerator;
136+
const lines = generator.generate();
137+
const fileType = i18n.t('vz-component-code-configmap-resource-title');
138+
const formatLabel = this.shellLabelMapper('resource-file-format');
139+
140+
window.api.ipc.send('download-file', lines, fileType, 'yaml', formatLabel);
141+
};
111142
}
112143

113144
return VerrazzanoComponentCodeViewModel;

webui/src/js/viewModels/vz-install-code-view.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,27 @@ function (accUtils, ko, project, VerrazzanoInstallScriptGenerator, VerrazzanoIns
9292

9393
this.renderScript(this.selectedSubview());
9494

95+
this.downloadInstaller = () => {
96+
const format = this.shellScriptType();
97+
const generator = new VerrazzanoInstallScriptGenerator(format);
98+
const lines = generator.generate();
99+
const fileType = i18n.t('script-file-type-label', {
100+
type: i18n.t('nav-verrazzano'),
101+
subType: i18n.t('vz-install-code-script-title')
102+
});
103+
const formatLabel = this.shellLabelMapper(format + '-label');
104+
105+
window.api.ipc.send('download-file', lines, fileType, format, formatLabel);
106+
};
107+
108+
this.downloadResource = () => {
109+
const generator = this.vzInstallResourceGenerator;
110+
const lines = generator.generate();
111+
const fileType = i18n.t('vz-install-code-verrazzano-resource-title');
112+
const formatLabel = this.shellLabelMapper('resource-file-format');
113+
114+
window.api.ipc.send('download-file', lines, fileType, 'yaml', formatLabel);
115+
};
95116
}
96117

97118
return VerrazzanoInstallCodeViewModel;

webui/src/js/views/domain-code-view.html

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
Copyright (c) 2021, Oracle and/or its affiliates.
2+
Copyright (c) 2021, 2022, Oracle and/or its affiliates.
33
Licensed under The Universal Permissive License (UPL), Version 1.0 as shown at https://oss.oracle.com/licenses/upl/
44
-->
55
<div class="wkt-nested-tab-frame">
@@ -19,24 +19,37 @@
1919
on-value-changed="[[selectedSubviewValueChangedHandler]]"
2020
value="{{selectedSubview}}">
2121
<div slot="script" class="oj-panel wkt-code-view-platform-frame">
22-
<oj-form-layout max-columns="1" direction="row">
22+
<oj-form-layout max-columns="2" direction="row">
2323
<oj-select-single label-hint="[[shellLabelMapper('selector-label')]]"
2424
on-value-changed="[[shellScriptTypeSelectValueChangedHandler]]"
2525
value="{{shellScriptType}}"
2626
data="{{shellScriptTypesDP}}"
2727
help.instruction="[[shellLabelMapper('selector-help')]]">
2828
</oj-select-single>
29+
<oj-button chroming="callToAction" on-oj-action="[[downloadInstaller]]">
30+
<span><oj-bind-text value="[[shellLabelMapper('button-download')]]"></oj-bind-text></span>
31+
</oj-button>
2932
</oj-form-layout>
3033
<oj-text-area class="wkt-code-view" max-rows="100000" value="{{scriptText}}" readonly="true">
3134
</oj-text-area>
3235
</div>
3336

3437
<div slot="domain" class="oj-panel wkt-code-view-platform-frame">
38+
<oj-form-layout max-columns="2" direction="row">
39+
<oj-button chroming="callToAction" on-oj-action="[[downloadComponentResource]]">
40+
<span><oj-bind-text value="[[shellLabelMapper('button-download')]]"></oj-bind-text></span>
41+
</oj-button>
42+
</oj-form-layout>
3543
<oj-text-area class="wkt-code-view" max-rows="100000" value="{{domainText}}" readonly="true">
3644
</oj-text-area>
3745
</div>
3846

3947
<div slot="configMap" class="oj-panel wkt-code-view-platform-frame">
48+
<oj-form-layout max-columns="2" direction="row">
49+
<oj-button chroming="callToAction" on-oj-action="[[downloadConfigMap]]">
50+
<span><oj-bind-text value="[[shellLabelMapper('button-download')]]"></oj-bind-text></span>
51+
</oj-button>
52+
</oj-form-layout>
4053
<oj-text-area class="wkt-code-view" max-rows="100000" value="{{configMapText}}" readonly="true">
4154
</oj-text-area>
4255
</div>

webui/src/js/views/image-code-view.html

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@
1818
class="wkt-code-view-switcher"
1919
value="{{tabsStatus}}">
2020
<div slot="enabled" class="oj-panel wkt-code-view-platform-frame">
21-
<oj-form-layout max-columns="1" direction="row">
21+
<oj-form-layout max-columns="2" direction="row">
2222
<oj-select-single label-hint="Script Language"
2323
on-value-changed="[[codeViewScriptLanguageSelectValueChangedHandler]]"
2424
value="{{codeViewScriptLanguage}}"
2525
data="[[codeViewScriptLanguagesDP]]"
2626
help.instruction="The scripting language to show.">
2727
</oj-select-single>
28+
<oj-button chroming="callToAction" on-oj-action="[[downloadScript]]">
29+
<span><oj-bind-text value="[[shellLabelMapper('button-download')]]"></oj-bind-text></span>
30+
</oj-button>
2831
</oj-form-layout>
2932
<oj-text-area class="wkt-code-view"
3033
max-rows="100000"

0 commit comments

Comments
 (0)