diff --git a/.gitignore b/.gitignore
index 5fe00fea85e..85050a25140 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
out
node_modules
+.DS_Store
.vscode-test/
*.vsix
diff --git a/build-scripts/bundleDeps.js b/build-scripts/bundleDeps.js
new file mode 100644
index 00000000000..712dcd76691
--- /dev/null
+++ b/build-scripts/bundleDeps.js
@@ -0,0 +1,32 @@
+'use strict';
+/*
+ This script is called from npm run compile.
+ It adds clientside libraries to ./media/libs.
+*/
+const fs = require('fs-extra');
+const path = require('path');
+const _ = require('lodash');
+
+const DEPS = [{
+ name: 'vue.min.js',
+ path: 'vue/dist/vue.min.js'
+ }
+];
+const workingDir = path.join(__dirname, '..');
+const nodeModulesDir = path.join(workingDir, 'node_modules');
+const libraryDir = path.join(workingDir, 'media', 'libs');
+(async () => {
+ const work = [];
+ _.forEach(DEPS, (dep) => {
+ const depPath = path.join(nodeModulesDir, dep.path);
+ console.log(`Copying ${depPath} to ${libraryDir}`);
+ work.push(fs.copy(depPath, path.join(libraryDir, dep.name)));
+ });
+ try {
+ await Promise.all(work);
+ console.log('Successfully copied all clientside dependencies.');
+ } catch (e) {
+ console.error('Error when copying clientside dependencies.');
+ console.error(e);
+ }
+})();
\ No newline at end of file
diff --git a/media/js/sampleRequests.js b/media/js/sampleRequests.js
new file mode 100644
index 00000000000..f5136f29ff2
--- /dev/null
+++ b/media/js/sampleRequests.js
@@ -0,0 +1,44 @@
+console.log('Loaded!');
+(function () {
+ const vscode = acquireVsCodeApi();
+ const app = new Vue({
+ el: '#app',
+ data: {
+ selectedSampleRequest: {},
+ sampleText: ""
+ },
+ mounted() {
+ this.$nextTick(function () {
+ window.addEventListener('message', this.handleMessageReceived);
+ })
+ },
+ methods: {
+ newSelection: function () {
+ vscode.postMessage({
+ command: 'sampleRequestSelected',
+ value: this.selectedSampleRequest
+ })
+ },
+ handleMessageReceived: function (e) {
+ const message = event.data;
+ console.log(message.command);
+ console.log(message.sample);
+ switch (message.command) {
+ case 'loadedSample':
+ this.loadSampleText(message.sample);
+ break;
+ }
+ },
+ loadSampleText: function (txt) {
+ this.sampleText = txt;
+ },
+ sendInput: function() {
+ console.log(this.sampleText);
+ vscode.postMessage({
+ command: 'invokeLambda',
+ value: this.sampleText
+ })
+ }
+ }
+ });
+})();
\ No newline at end of file
diff --git a/media/libs/vue.min.js b/media/libs/vue.min.js
new file mode 100644
index 00000000000..37febff24c6
--- /dev/null
+++ b/media/libs/vue.min.js
@@ -0,0 +1,6 @@
+/*!
+ * Vue.js v2.5.16
+ * (c) 2014-2018 Evan You
+ * Released under the MIT License.
+ */
+!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Vue=t()}(this,function(){"use strict";var y=Object.freeze({});function M(e){return null==e}function D(e){return null!=e}function S(e){return!0===e}function T(e){return"string"==typeof e||"number"==typeof e||"symbol"==typeof e||"boolean"==typeof e}function P(e){return null!==e&&"object"==typeof e}var r=Object.prototype.toString;function l(e){return"[object Object]"===r.call(e)}function i(e){var t=parseFloat(String(e));return 0<=t&&Math.floor(t)===t&&isFinite(e)}function t(e){return null==e?"":"object"==typeof e?JSON.stringify(e,null,2):String(e)}function F(e){var t=parseFloat(e);return isNaN(t)?e:t}function s(e,t){for(var n=Object.create(null),r=e.split(","),i=0;i Status Code: <%= StatusCode %> Response:
- -1"+("true"===d?":("+l+")":":_q("+l+","+d+")")),Ar(c,"change","var $$a="+l+",$$el=$event.target,$$c=$$el.checked?("+d+"):("+v+");if(Array.isArray($$a)){var $$v="+(f?"_n("+p+")":p)+",$$i=_i($$a,$$v);if($$el.checked){$$i<0&&("+Er(l,"$$a.concat([$$v])")+")}else{$$i>-1&&("+Er(l,"$$a.slice(0,$$i).concat($$a.slice($$i+1))")+")}}else{"+Er(l,"$$c")+"}",null,!0);else if("input"===$&&"radio"===w)r=e,i=_,a=(o=b)&&o.number,s=Or(r,"value")||"null",Cr(r,"checked","_q("+i+","+(s=a?"_n("+s+")":s)+")"),Ar(r,"change",Er(i,s),null,!0);else if("input"===$||"textarea"===$)!function(e,t,n){var r=e.attrsMap.type,i=n||{},o=i.lazy,a=i.number,s=i.trim,c=!o&&"range"!==r,l=o?"change":"range"===r?Pr:"input",u="$event.target.value";s&&(u="$event.target.value.trim()"),a&&(u="_n("+u+")");var f=Er(t,u);c&&(f="if($event.target.composing)return;"+f),Cr(e,"value","("+t+")"),Ar(e,l,f,null,!0),(s||a)&&Ar(e,"blur","$forceUpdate()")}(e,_,b);else if(!j.isReservedTag($))return Tr(e,_,b),!1;return!0},text:function(e,t){t.value&&Cr(e,"textContent","_s("+t.value+")")},html:function(e,t){t.value&&Cr(e,"innerHTML","_s("+t.value+")")}},isPreTag:function(e){return"pre"===e},isUnaryTag:to,mustUseProp:Sn,canBeLeftOpenTag:no,isReservedTag:Un,getTagNamespace:Vn,staticKeys:(Go=Wo,Go.reduce(function(e,t){return e.concat(t.staticKeys||[])},[]).join(","))},Qo=e(function(e){return s("type,tag,attrsList,attrsMap,plain,parent,children,attrs"+(e?","+e:""))});function ea(e,t){e&&(Zo=Qo(t.staticKeys||""),Xo=t.isReservedTag||O,function e(t){t.static=function(e){if(2===e.type)return!1;if(3===e.type)return!0;return!(!e.pre&&(e.hasBindings||e.if||e.for||c(e.tag)||!Xo(e.tag)||function(e){for(;e.parent;){if("template"!==(e=e.parent).tag)return!1;if(e.for)return!0}return!1}(e)||!Object.keys(e).every(Zo)))}(t);if(1===t.type){if(!Xo(t.tag)&&"slot"!==t.tag&&null==t.attrsMap["inline-template"])return;for(var n=0,r=t.children.length;nLoading...
` });
+ view.webview.html = baseTemplateFn({
+ content: `Loading...
`
+ });
// ideally need to get the client from the explorer, but the context will do for now
- const lambdaClient = await ext.sdkClientBuilder.createAndConfigureSdkClient(Lambda, undefined);
- const funcResponse = await lambdaClient.invoke({ FunctionName: fn.functionConfiguration.FunctionArn!, LogType: 'Tail' }).promise();
- const logs = funcResponse.LogResult ? Buffer.from(funcResponse.LogResult, 'base64') : "";
- const payload = funcResponse.Payload ? funcResponse.Payload : JSON.stringify({});
- const invokeTemplateFn = _.template(LambdaTemplates.InvokeTemplate);
- view.webview.html = baseTemplateFn({
- content: invokeTemplateFn({
- FunctionName: fn.functionConfiguration.FunctionName,
- LogResult: logs,
- StatusCode: funcResponse.StatusCode,
- Payload: payload
- })
- });
+ console.log('building template...');
+ const invokeInputTemplateFn = _.template(LambdaTemplates.InvokeInputTemplate);
+ const resourcePath = path.join(ext.context.extensionPath, 'resources', 'vs-lambda-sample-request-manifest.xml');
+ console.log(sampleRequestManifestPath);
+ console.log(resourcePath);
+ try {
+ const sampleInput = await ResourceFetcher.fetchHostedResource(sampleRequestManifestPath, resourcePath);
+ const inputs: SampleRequest[] = [];
+ console.log('querying manifest url');
+ xml2js.parseString(sampleInput, { explicitArray: false }, (err, result) => {
+ console.log(result);
+ if (err) { return; }
+ _.forEach(result.requests.request, (r) => {
+ inputs.push({ name: r.name, filename: r.filename });
+ });
+ });
+ const loadScripts = ExtensionUtilities.getScriptsForHtml(['sampleRequests.js']);
+ const loadLibs = ExtensionUtilities.getLibrariesForHtml(['vue.min.js']);
+ console.log(loadLibs);
+ view.webview.html = baseTemplateFn({
+ content: invokeInputTemplateFn({
+ FunctionName: fn.functionConfiguration.FunctionName,
+ InputSamples: inputs,
+ Scripts: loadScripts,
+ Libraries: loadLibs
+ // LogResult: logs,
+ // StatusCode: funcResponse.StatusCode,
+ // Payload: payload
+ }),
+ });
+
+ view.webview.onDidReceiveMessage(async message => {
+ switch (message.command) {
+ case 'sampleRequestSelected':
+ console.log('selected the following sample:');
+ console.log(message.value);
+ const sample = await ResourceFetcher.fetchHostedResource(sampleRequestPath + message.value, resourcePath);
+ console.log(sample);
+ view.webview.postMessage({ command: 'loadedSample', sample: sample });
+ return;
+ case 'invokeLambda':
+ console.log('got the following payload:');
+ console.log(message.value);
+ const lambdaClient = await ext.sdkClientBuilder.createAndConfigureSdkClient(Lambda, undefined);
+ let funcRequest = {
+ FunctionName: fn.functionConfiguration.FunctionArn!,
+ LogType: 'Tail'
+ } as AWS.Lambda.InvocationRequest;
+ if (message.value) {
+ console.log('found a payload');
+ funcRequest.Payload = message.value;
+ }
+ const invokeTemplateFn = _.template(LambdaTemplates.InvokeTemplate);
+ try {
+ const funcResponse = await lambdaClient.invoke(funcRequest).promise();
+ const logs = funcResponse.LogResult ? Buffer.from(funcResponse.LogResult, 'base64') : "";
+ const payload = funcResponse.Payload ? funcResponse.Payload : JSON.stringify({});
+ view.webview.html = baseTemplateFn({
+ content: invokeTemplateFn({
+ FunctionName: fn.functionConfiguration.FunctionName,
+ LogResult: logs,
+ StatusCode: funcResponse.StatusCode,
+ Payload: payload
+ }),
+ });
+ } catch (e) {
+ view.webview.html = baseTemplateFn({
+ content: invokeTemplateFn({
+ FunctionName: fn.functionConfiguration.FunctionName,
+ LogResult: null,
+ StatusCode: null,
+ Payload: null,
+ Error: e
+ }),
+ });
+ }
+ break;
+ }
+ }, undefined, ext.context.subscriptions);
+ }
+ catch (err) {
+ console.log('Error getting manifest data..');
+ console.log(err);
+ }
}
catch (err) {
const ex: AWSError = err;
diff --git a/src/lambda/constants.ts b/src/lambda/constants.ts
index 4e046675de6..672edb3579e 100644
--- a/src/lambda/constants.ts
+++ b/src/lambda/constants.ts
@@ -1,3 +1,7 @@
'use strict';
+import { hostedFilesBaseUrl } from "../shared/constants";
export const blueprintsManifestPath: string = 'LambdaSampleFunctions/NETCore/msbuild-v4/vs-lambda-blueprint-manifest.xml';
+export const sampleRequestBase: string = 'LambdaSampleFunctions/SampleRequests';
+export const sampleRequestPath: string = `${hostedFilesBaseUrl}${sampleRequestBase}/`;
+export const sampleRequestManifestPath: string = `${hostedFilesBaseUrl}${sampleRequestBase}/manifest.xml`;
diff --git a/src/lambda/models/sampleRequest.ts b/src/lambda/models/sampleRequest.ts
new file mode 100644
index 00000000000..e61bf67f3ab
--- /dev/null
+++ b/src/lambda/models/sampleRequest.ts
@@ -0,0 +1,4 @@
+export class SampleRequest {
+ public name: string | undefined;
+ public filename: string | undefined;
+}
\ No newline at end of file
diff --git a/src/lambda/models/scriptResource.ts b/src/lambda/models/scriptResource.ts
new file mode 100644
index 00000000000..3e367fd8812
--- /dev/null
+++ b/src/lambda/models/scriptResource.ts
@@ -0,0 +1,5 @@
+import * as vscode from 'vscode';
+export class ScriptResource {
+ public Uri: vscode.Uri | undefined;
+ public Nonce: string | undefined;
+}
\ No newline at end of file
diff --git a/src/lambda/templates/lambdaTemplates.ts b/src/lambda/templates/lambdaTemplates.ts
index 6423332c653..0c4ce1ed9f1 100644
--- a/src/lambda/templates/lambdaTemplates.ts
+++ b/src/lambda/templates/lambdaTemplates.ts
@@ -1,15 +1,52 @@
export class LambdaTemplates {
+ static readonly InvokeInputTemplate = `
+
+ Include input payload with <%= FunctionName %>
+
+
+ Use an input template:
+
+
+
+
+
+
+
Invoking <%= FunctionName %>...
- <%- JSON.stringify(JSON.parse(Payload), null, 4) %>
-
Logs: -
<%= LogResult %>- + <% if (Error) { %> +
Something went wrong.
+<%= Error %>+
Status Code: <%= StatusCode %>
+Response: +
<%- JSON.stringify(JSON.parse(Payload), null, 4) %>+ +
Logs: +
<%= LogResult %>+ + <% } %> `; static readonly GetPolicyTemplate = `