mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-07 11:36:47 +00:00
Compare commits
14 Commits
make_accou
...
languy-upg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d94849c7b | ||
|
|
8285f1fc37 | ||
|
|
1e6ad113dd | ||
|
|
05932e1d38 | ||
|
|
02e6d8442b | ||
|
|
8cf09acc19 | ||
|
|
5cd4e93c65 | ||
|
|
76e3b7e6f1 | ||
|
|
dc5679ffd3 | ||
|
|
88f5e7485a | ||
|
|
662c03580a | ||
|
|
14fd9054dd | ||
|
|
ad1d5add96 | ||
|
|
c9be25b1e8 |
@@ -135,7 +135,6 @@ src/Explorer/Panes/SwitchDirectoryPane.ts
|
|||||||
src/Explorer/Panes/Tables/AddTableEntityPane.ts
|
src/Explorer/Panes/Tables/AddTableEntityPane.ts
|
||||||
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
||||||
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
||||||
src/Explorer/Panes/Tables/QuerySelectPane.ts
|
|
||||||
src/Explorer/Panes/Tables/TableEntityPane.ts
|
src/Explorer/Panes/Tables/TableEntityPane.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
||||||
@@ -299,8 +298,6 @@ src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.test.t
|
|||||||
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.tsx
|
src/Explorer/Graph/GraphExplorerComponent/ReadOnlyNodePropertiesComponent.tsx
|
||||||
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
|
src/Explorer/Menus/CommandBar/CommandBarUtil.tsx
|
||||||
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.test.tsx
|
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.test.tsx
|
||||||
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponent.tsx
|
|
||||||
src/Explorer/Menus/NotificationConsole/NotificationConsoleComponentAdapter.tsx
|
|
||||||
src/Explorer/Notebook/NotebookComponent/NotebookComponent.tsx
|
src/Explorer/Notebook/NotebookComponent/NotebookComponent.tsx
|
||||||
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
|
src/Explorer/Notebook/NotebookComponent/NotebookComponentAdapter.tsx
|
||||||
src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
|
src/Explorer/Notebook/NotebookComponent/NotebookComponentBootstrapper.tsx
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module.exports = {
|
|||||||
browser: true,
|
browser: true,
|
||||||
es6: true,
|
es6: true,
|
||||||
},
|
},
|
||||||
plugins: ["@typescript-eslint", "no-null", "prefer-arrow"],
|
plugins: ["@typescript-eslint", "no-null", "prefer-arrow", "react-hooks"],
|
||||||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
||||||
globals: {
|
globals: {
|
||||||
Atomics: "readonly",
|
Atomics: "readonly",
|
||||||
@@ -20,7 +20,7 @@ module.exports = {
|
|||||||
overrides: [
|
overrides: [
|
||||||
{
|
{
|
||||||
files: ["**/*.tsx"],
|
files: ["**/*.tsx"],
|
||||||
extends: ["plugin:react/recommended"], // TODO: Add react-hooks
|
extends: ["plugin:react/recommended"],
|
||||||
plugins: ["react"],
|
plugins: ["react"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -42,6 +42,8 @@ module.exports = {
|
|||||||
"prefer-arrow/prefer-arrow-functions": ["error", { allowStandaloneDeclarations: true }],
|
"prefer-arrow/prefer-arrow-functions": ["error", { allowStandaloneDeclarations: true }],
|
||||||
eqeqeq: "error",
|
eqeqeq: "error",
|
||||||
"react/display-name": "off",
|
"react/display-name": "off",
|
||||||
|
"react-hooks/rules-of-hooks": "warn", // TODO: error
|
||||||
|
"react-hooks/exhaustive-deps": "warn", // TODO: error
|
||||||
"no-restricted-syntax": [
|
"no-restricted-syntax": [
|
||||||
"error",
|
"error",
|
||||||
{
|
{
|
||||||
|
|||||||
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
1
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
[Preview this branch](https://cosmos-explorer-preview.azurewebsites.net/pull/EDIT_THIS_NUMBER_IN_THE_PR_DESCRIPTION?feature.someFeatureFlagYouMightNeed=true)
|
||||||
6201
package-lock.json
generated
6201
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -25,12 +25,12 @@
|
|||||||
"@nteract/iron-icons": "1.0.0",
|
"@nteract/iron-icons": "1.0.0",
|
||||||
"@nteract/jupyter-widgets": "2.0.0",
|
"@nteract/jupyter-widgets": "2.0.0",
|
||||||
"@nteract/logos": "1.0.0",
|
"@nteract/logos": "1.0.0",
|
||||||
"@nteract/markdown": "4.4.0",
|
"@nteract/markdown": "4.6.1",
|
||||||
"@nteract/monaco-editor": "3.2.2",
|
"@nteract/monaco-editor": "3.2.2",
|
||||||
"@nteract/octicons": "2.0.0",
|
"@nteract/octicons": "2.0.0",
|
||||||
"@nteract/outputs": "3.0.9",
|
"@nteract/outputs": "3.0.9",
|
||||||
"@nteract/presentational-components": "3.0.7",
|
"@nteract/presentational-components": "3.0.7",
|
||||||
"@nteract/stateful-components": "1.7.0",
|
"@nteract/stateful-components": "1.7.7",
|
||||||
"@nteract/styles": "2.0.2",
|
"@nteract/styles": "2.0.2",
|
||||||
"@nteract/transform-geojson": "5.1.8",
|
"@nteract/transform-geojson": "5.1.8",
|
||||||
"@nteract/transform-model-debug": "5.0.1",
|
"@nteract/transform-model-debug": "5.0.1",
|
||||||
@@ -200,8 +200,8 @@
|
|||||||
"format:check": "prettier --check \"{src,test}/**/*.{ts,tsx,html}\" \"*.{js,html}\"",
|
"format:check": "prettier --check \"{src,test}/**/*.{ts,tsx,html}\" \"*.{js,html}\"",
|
||||||
"lint": "tslint --project tsconfig.json && eslint \"**/*.{ts,tsx}\"",
|
"lint": "tslint --project tsconfig.json && eslint \"**/*.{ts,tsx}\"",
|
||||||
"build:contracts": "npm run compile:contracts",
|
"build:contracts": "npm run compile:contracts",
|
||||||
"strictEligibleFiles": "node ./strict-migration-tools/index.js",
|
"strict:find": "node ./strict-null-checks/find.js",
|
||||||
"autoAddStrictEligibleFiles": "node ./strict-migration-tools/autoAdd.js",
|
"strict:add": "node ./strict-null-checks/auto-add.js",
|
||||||
"compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks",
|
"compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks",
|
||||||
"generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts"
|
"generateARMClients": "ts-node --compiler-options '{\"module\":\"commonjs\"}' utils/armClientGenerator/generator.ts"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const express = require("express");
|
const express = require("express");
|
||||||
const { createProxyMiddleware } = require("http-proxy-middleware");
|
const { createProxyMiddleware } = require("http-proxy-middleware");
|
||||||
const port = process.env.PORT || 3000;
|
const port = process.env.PORT || 3000;
|
||||||
|
const fetch = require("node-fetch");
|
||||||
|
|
||||||
const api = createProxyMiddleware("/api", {
|
const api = createProxyMiddleware("/api", {
|
||||||
target: "https://main.documentdb.ext.azure.com",
|
target: "https://main.documentdb.ext.azure.com",
|
||||||
@@ -39,6 +40,31 @@ const app = express();
|
|||||||
app.use(api);
|
app.use(api);
|
||||||
app.use(proxy);
|
app.use(proxy);
|
||||||
app.use(commit);
|
app.use(commit);
|
||||||
|
app.get("/pull/:pr(\\d+)", (req, res) => {
|
||||||
|
const pr = req.params.pr;
|
||||||
|
const [, query] = req.originalUrl.split("?");
|
||||||
|
const search = new URLSearchParams(query);
|
||||||
|
|
||||||
|
fetch("https://api.github.com/repos/Azure/cosmos-explorer/pulls/" + pr)
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then(({ head: { ref, sha } }) => {
|
||||||
|
const prUrl = new URL("https://github.com/Azure/cosmos-explorer/pull/" + pr);
|
||||||
|
prUrl.hash = ref;
|
||||||
|
search.set("feature.pr", prUrl.href);
|
||||||
|
|
||||||
|
const explorer = new URL("https://cosmos-explorer-preview.azurewebsites.net/commit/" + sha + "/explorer.html");
|
||||||
|
explorer.search = search.toString();
|
||||||
|
|
||||||
|
const portal = new URL("https://ms.portal.azure.com/");
|
||||||
|
portal.searchParams.set("dataExplorerSource", explorer.href);
|
||||||
|
portal.hash =
|
||||||
|
"@microsoft.onmicrosoft.com/resource/subscriptions/b9c77f10-b438-4c32-9819-eef8a654e478/resourceGroups/stfaul/providers/Microsoft.DocumentDb/databaseAccounts/stfaul-sql/dataExplorer";
|
||||||
|
|
||||||
|
return res.redirect(portal.href);
|
||||||
|
})
|
||||||
|
.catch(() => res.sendStatus(500));
|
||||||
|
});
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Example app listening on port: ${port}`);
|
console.log(`Example app listening on port: ${port}`);
|
||||||
});
|
});
|
||||||
|
|||||||
659
preview/package-lock.json
generated
659
preview/package-lock.json
generated
@@ -1,8 +1,658 @@
|
|||||||
{
|
{
|
||||||
"name": "preview",
|
"name": "cosmos-explorer-preview",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "cosmos-explorer-preview",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"http-proxy-middleware": "^1.1.0",
|
||||||
|
"node-fetch": "^2.6.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/http-proxy": {
|
||||||
|
"version": "1.17.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.5.tgz",
|
||||||
|
"integrity": "sha512-GNkDE7bTv6Sf8JbV2GksknKOsk7OznNYHSdrtvPJXO0qJ9odZig6IZKUi5RFGi6d1bf6dgIAe4uXi3DBc7069Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "14.14.37",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.37.tgz",
|
||||||
|
"integrity": "sha512-XYmBiy+ohOR4Lh5jE379fV2IU+6Jn4g5qASinhitfyO71b/sCo6MKsMLF5tc7Zf2CE8hViVQyYSobJNke8OvUw=="
|
||||||
|
},
|
||||||
|
"node_modules/accepts": {
|
||||||
|
"version": "1.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
|
||||||
|
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-types": "~2.1.24",
|
||||||
|
"negotiator": "0.6.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/array-flatten": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||||
|
},
|
||||||
|
"node_modules/body-parser": {
|
||||||
|
"version": "1.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
|
||||||
|
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
|
||||||
|
"dependencies": {
|
||||||
|
"bytes": "3.1.0",
|
||||||
|
"content-type": "~1.0.4",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"http-errors": "1.7.2",
|
||||||
|
"iconv-lite": "0.4.24",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"qs": "6.7.0",
|
||||||
|
"raw-body": "2.4.0",
|
||||||
|
"type-is": "~1.6.17"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/braces": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||||
|
"dependencies": {
|
||||||
|
"fill-range": "^7.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/bytes": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/camelcase": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/content-disposition": {
|
||||||
|
"version": "0.5.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
|
||||||
|
"integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "5.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/content-type": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cookie": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cookie-signature": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||||
|
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
|
||||||
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "2.6.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||||
|
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/depd": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/destroy": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||||
|
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||||
|
},
|
||||||
|
"node_modules/ee-first": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
|
||||||
|
},
|
||||||
|
"node_modules/encodeurl": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/escape-html": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
|
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||||
|
},
|
||||||
|
"node_modules/etag": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||||
|
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/eventemitter3": {
|
||||||
|
"version": "4.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
|
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
|
||||||
|
},
|
||||||
|
"node_modules/express": {
|
||||||
|
"version": "4.17.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
|
||||||
|
"integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
|
||||||
|
"dependencies": {
|
||||||
|
"accepts": "~1.3.7",
|
||||||
|
"array-flatten": "1.1.1",
|
||||||
|
"body-parser": "1.19.0",
|
||||||
|
"content-disposition": "0.5.3",
|
||||||
|
"content-type": "~1.0.4",
|
||||||
|
"cookie": "0.4.0",
|
||||||
|
"cookie-signature": "1.0.6",
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"etag": "~1.8.1",
|
||||||
|
"finalhandler": "~1.1.2",
|
||||||
|
"fresh": "0.5.2",
|
||||||
|
"merge-descriptors": "1.0.1",
|
||||||
|
"methods": "~1.1.2",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"parseurl": "~1.3.3",
|
||||||
|
"path-to-regexp": "0.1.7",
|
||||||
|
"proxy-addr": "~2.0.5",
|
||||||
|
"qs": "6.7.0",
|
||||||
|
"range-parser": "~1.2.1",
|
||||||
|
"safe-buffer": "5.1.2",
|
||||||
|
"send": "0.17.1",
|
||||||
|
"serve-static": "1.14.1",
|
||||||
|
"setprototypeof": "1.1.1",
|
||||||
|
"statuses": "~1.5.0",
|
||||||
|
"type-is": "~1.6.18",
|
||||||
|
"utils-merge": "1.0.1",
|
||||||
|
"vary": "~1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fill-range": {
|
||||||
|
"version": "7.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||||
|
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"to-regex-range": "^5.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/finalhandler": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"parseurl": "~1.3.3",
|
||||||
|
"statuses": "~1.5.0",
|
||||||
|
"unpipe": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/follow-redirects": {
|
||||||
|
"version": "1.13.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
|
||||||
|
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/forwarded": {
|
||||||
|
"version": "0.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||||
|
"integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fresh": {
|
||||||
|
"version": "0.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||||
|
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-errors": {
|
||||||
|
"version": "1.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
|
||||||
|
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
|
||||||
|
"dependencies": {
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"inherits": "2.0.3",
|
||||||
|
"setprototypeof": "1.1.1",
|
||||||
|
"statuses": ">= 1.5.0 < 2",
|
||||||
|
"toidentifier": "1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-proxy": {
|
||||||
|
"version": "1.18.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||||
|
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"eventemitter3": "^4.0.0",
|
||||||
|
"follow-redirects": "^1.0.0",
|
||||||
|
"requires-port": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/http-proxy-middleware": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-OnjU5vyVgcZVe2AjLJyMrk8YLNOC2lspCHirB5ldM+B/dwEfZ5bgVTrFyzE9R7xRWAP/i/FXtvIqKjTNEZBhBg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/http-proxy": "^1.17.5",
|
||||||
|
"camelcase": "^6.2.0",
|
||||||
|
"http-proxy": "^1.18.1",
|
||||||
|
"is-glob": "^4.0.1",
|
||||||
|
"is-plain-obj": "^3.0.0",
|
||||||
|
"micromatch": "^4.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/iconv-lite": {
|
||||||
|
"version": "0.4.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||||
|
"dependencies": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/inherits": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||||
|
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
||||||
|
},
|
||||||
|
"node_modules/ipaddr.js": {
|
||||||
|
"version": "1.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
|
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-extglob": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
|
||||||
|
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-glob": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-extglob": "^2.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-number": {
|
||||||
|
"version": "7.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||||
|
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/is-plain-obj": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/media-typer": {
|
||||||
|
"version": "0.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
|
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/merge-descriptors": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
|
||||||
|
},
|
||||||
|
"node_modules/methods": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/micromatch": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"braces": "^3.0.1",
|
||||||
|
"picomatch": "^2.0.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime": {
|
||||||
|
"version": "1.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||||
|
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||||
|
"bin": {
|
||||||
|
"mime": "cli.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-db": {
|
||||||
|
"version": "1.46.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.46.0.tgz",
|
||||||
|
"integrity": "sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mime-types": {
|
||||||
|
"version": "2.1.29",
|
||||||
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.29.tgz",
|
||||||
|
"integrity": "sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"mime-db": "1.46.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
},
|
||||||
|
"node_modules/negotiator": {
|
||||||
|
"version": "0.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||||
|
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "2.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||||
|
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
|
||||||
|
"engines": {
|
||||||
|
"node": "4.x || >=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/on-finished": {
|
||||||
|
"version": "2.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
"integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
|
||||||
|
"dependencies": {
|
||||||
|
"ee-first": "1.1.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/parseurl": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/path-to-regexp": {
|
||||||
|
"version": "0.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||||
|
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
|
||||||
|
},
|
||||||
|
"node_modules/picomatch": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/proxy-addr": {
|
||||||
|
"version": "2.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
|
||||||
|
"integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
|
||||||
|
"dependencies": {
|
||||||
|
"forwarded": "~0.1.2",
|
||||||
|
"ipaddr.js": "1.9.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/qs": {
|
||||||
|
"version": "6.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
|
||||||
|
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/range-parser": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/raw-body": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"bytes": "3.1.0",
|
||||||
|
"http-errors": "1.7.2",
|
||||||
|
"iconv-lite": "0.4.24",
|
||||||
|
"unpipe": "1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/requires-port": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
|
||||||
|
},
|
||||||
|
"node_modules/safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
|
"node_modules/safer-buffer": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
|
},
|
||||||
|
"node_modules/send": {
|
||||||
|
"version": "0.17.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
|
||||||
|
"integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
|
||||||
|
"dependencies": {
|
||||||
|
"debug": "2.6.9",
|
||||||
|
"depd": "~1.1.2",
|
||||||
|
"destroy": "~1.0.4",
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"etag": "~1.8.1",
|
||||||
|
"fresh": "0.5.2",
|
||||||
|
"http-errors": "~1.7.2",
|
||||||
|
"mime": "1.6.0",
|
||||||
|
"ms": "2.1.1",
|
||||||
|
"on-finished": "~2.3.0",
|
||||||
|
"range-parser": "~1.2.1",
|
||||||
|
"statuses": "~1.5.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/send/node_modules/ms": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
|
||||||
|
},
|
||||||
|
"node_modules/serve-static": {
|
||||||
|
"version": "1.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
|
||||||
|
"integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
|
||||||
|
"dependencies": {
|
||||||
|
"encodeurl": "~1.0.2",
|
||||||
|
"escape-html": "~1.0.3",
|
||||||
|
"parseurl": "~1.3.3",
|
||||||
|
"send": "0.17.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/setprototypeof": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
|
||||||
|
},
|
||||||
|
"node_modules/statuses": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
|
||||||
|
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/to-regex-range": {
|
||||||
|
"version": "5.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-number": "^7.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/toidentifier": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/type-is": {
|
||||||
|
"version": "1.6.18",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||||
|
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||||
|
"dependencies": {
|
||||||
|
"media-typer": "0.3.0",
|
||||||
|
"mime-types": "~2.1.24"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/unpipe": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/utils-merge": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vary": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||||
|
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/http-proxy": {
|
"@types/http-proxy": {
|
||||||
"version": "1.17.5",
|
"version": "1.17.5",
|
||||||
@@ -334,6 +984,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
|
||||||
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
||||||
},
|
},
|
||||||
|
"node-fetch": {
|
||||||
|
"version": "2.6.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||||
|
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||||
|
},
|
||||||
"on-finished": {
|
"on-finished": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
"author": "Microsoft Corporation",
|
"author": "Microsoft Corporation",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"http-proxy-middleware": "^1.1.0"
|
"http-proxy-middleware": "^1.1.0",
|
||||||
|
"node-fetch": "^2.6.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import * as DataModels from "../../Contracts/DataModels";
|
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
|
import * as DataModels from "../../Contracts/DataModels";
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import { client } from "../CosmosClient";
|
import { userContext } from "../../UserContext";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
|
||||||
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
import { listCassandraTables } from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
import { listGremlinGraphs } from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import { listMongoDBCollections } from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { listSqlContainers } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { listTables } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
||||||
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
||||||
@@ -17,7 +17,6 @@ export async function readCollections(databaseId: string): Promise<DataModels.Co
|
|||||||
if (
|
if (
|
||||||
userContext.authType === AuthType.AAD &&
|
userContext.authType === AuthType.AAD &&
|
||||||
!userContext.useSDKOperations &&
|
!userContext.useSDKOperations &&
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.MongoDB &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
) {
|
) {
|
||||||
return await readCollectionsWithARM(databaseId);
|
return await readCollectionsWithARM(databaseId);
|
||||||
|
|||||||
@@ -1,39 +1,37 @@
|
|||||||
|
import { ContainerDefinition } from "@azure/cosmos";
|
||||||
|
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||||
import { AuthType } from "../../AuthType";
|
import { AuthType } from "../../AuthType";
|
||||||
import { Collection } from "../../Contracts/DataModels";
|
import { Collection } from "../../Contracts/DataModels";
|
||||||
import { ContainerDefinition } from "@azure/cosmos";
|
|
||||||
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
import { DefaultAccountExperienceType } from "../../DefaultAccountExperienceType";
|
||||||
import {
|
import { userContext } from "../../UserContext";
|
||||||
CreateUpdateOptions,
|
|
||||||
ExtendedResourceProperties,
|
|
||||||
MongoDBCollectionCreateUpdateParameters,
|
|
||||||
MongoDBCollectionResource,
|
|
||||||
SqlContainerCreateUpdateParameters,
|
|
||||||
SqlContainerResource,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
|
||||||
import { client } from "../CosmosClient";
|
|
||||||
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateCassandraTable,
|
createUpdateCassandraTable,
|
||||||
getCassandraTable,
|
getCassandraTable,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/cassandraResources";
|
||||||
import {
|
|
||||||
createUpdateMongoDBCollection,
|
|
||||||
getMongoDBCollection,
|
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
|
||||||
import {
|
import {
|
||||||
createUpdateGremlinGraph,
|
createUpdateGremlinGraph,
|
||||||
getGremlinGraph,
|
getGremlinGraph,
|
||||||
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
} from "../../Utils/arm/generatedClients/2020-04-01/gremlinResources";
|
||||||
|
import {
|
||||||
|
createUpdateMongoDBCollection,
|
||||||
|
getMongoDBCollection,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/mongoDBResources";
|
||||||
|
import { createUpdateSqlContainer, getSqlContainer } from "../../Utils/arm/generatedClients/2020-04-01/sqlResources";
|
||||||
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
import { createUpdateTable, getTable } from "../../Utils/arm/generatedClients/2020-04-01/tableResources";
|
||||||
import { handleError } from "../ErrorHandlingUtils";
|
import {
|
||||||
|
ExtendedResourceProperties,
|
||||||
|
MongoDBCollectionCreateUpdateParameters,
|
||||||
|
SqlContainerCreateUpdateParameters,
|
||||||
|
SqlContainerResource,
|
||||||
|
} from "../../Utils/arm/generatedClients/2020-04-01/types";
|
||||||
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||||
import { userContext } from "../../UserContext";
|
import { client } from "../CosmosClient";
|
||||||
|
import { handleError } from "../ErrorHandlingUtils";
|
||||||
|
|
||||||
export async function updateCollection(
|
export async function updateCollection(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
newCollection: Collection,
|
newCollection: Partial<Collection>,
|
||||||
options: RequestOptions = {}
|
options: RequestOptions = {}
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
let collection: Collection;
|
let collection: Collection;
|
||||||
@@ -43,7 +41,6 @@ export async function updateCollection(
|
|||||||
if (
|
if (
|
||||||
userContext.authType === AuthType.AAD &&
|
userContext.authType === AuthType.AAD &&
|
||||||
!userContext.useSDKOperations &&
|
!userContext.useSDKOperations &&
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.MongoDB &&
|
|
||||||
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
userContext.defaultExperience !== DefaultAccountExperienceType.Table
|
||||||
) {
|
) {
|
||||||
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
||||||
@@ -69,7 +66,7 @@ export async function updateCollection(
|
|||||||
async function updateCollectionWithARM(
|
async function updateCollectionWithARM(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
newCollection: Collection
|
newCollection: Partial<Collection>
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const subscriptionId = userContext.subscriptionId;
|
const subscriptionId = userContext.subscriptionId;
|
||||||
const resourceGroup = userContext.resourceGroup;
|
const resourceGroup = userContext.resourceGroup;
|
||||||
@@ -85,6 +82,15 @@ async function updateCollectionWithARM(
|
|||||||
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateGremlinGraph(databaseId, collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
case DefaultAccountExperienceType.Table:
|
case DefaultAccountExperienceType.Table:
|
||||||
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
return updateTable(collectionId, subscriptionId, resourceGroup, accountName, newCollection);
|
||||||
|
case DefaultAccountExperienceType.MongoDB:
|
||||||
|
return updateMongoDBCollection(
|
||||||
|
databaseId,
|
||||||
|
collectionId,
|
||||||
|
subscriptionId,
|
||||||
|
resourceGroup,
|
||||||
|
accountName,
|
||||||
|
newCollection
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
throw new Error(`Unsupported default experience type: ${defaultExperience}`);
|
||||||
}
|
}
|
||||||
@@ -96,7 +102,7 @@ async function updateSqlContainer(
|
|||||||
subscriptionId: string,
|
subscriptionId: string,
|
||||||
resourceGroup: string,
|
resourceGroup: string,
|
||||||
accountName: string,
|
accountName: string,
|
||||||
newCollection: Collection
|
newCollection: Partial<Collection>
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const getResponse = await getSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
const getResponse = await getSqlContainer(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
@@ -115,35 +121,26 @@ async function updateSqlContainer(
|
|||||||
throw new Error(`Sql container to update does not exist. Database id: ${databaseId} Collection id: ${collectionId}`);
|
throw new Error(`Sql container to update does not exist. Database id: ${databaseId} Collection id: ${collectionId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateMongoDBCollectionThroughRP(
|
export async function updateMongoDBCollection(
|
||||||
databaseId: string,
|
databaseId: string,
|
||||||
collectionId: string,
|
collectionId: string,
|
||||||
newCollection: MongoDBCollectionResource,
|
subscriptionId: string,
|
||||||
updateOptions?: CreateUpdateOptions
|
resourceGroup: string,
|
||||||
): Promise<MongoDBCollectionResource> {
|
accountName: string,
|
||||||
const subscriptionId = userContext.subscriptionId;
|
newCollection: Partial<Collection>
|
||||||
const resourceGroup = userContext.resourceGroup;
|
): Promise<Collection> {
|
||||||
const accountName = userContext.databaseAccount.name;
|
|
||||||
|
|
||||||
const getResponse = await getMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
const getResponse = await getMongoDBCollection(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
const updateParams: MongoDBCollectionCreateUpdateParameters = {
|
getResponse.properties.resource = newCollection as SqlContainerResource & ExtendedResourceProperties;
|
||||||
properties: {
|
|
||||||
resource: newCollection,
|
|
||||||
options: updateOptions,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateResponse = await createUpdateMongoDBCollection(
|
const updateResponse = await createUpdateMongoDBCollection(
|
||||||
subscriptionId,
|
subscriptionId,
|
||||||
resourceGroup,
|
resourceGroup,
|
||||||
accountName,
|
accountName,
|
||||||
databaseId,
|
databaseId,
|
||||||
collectionId,
|
collectionId,
|
||||||
updateParams
|
getResponse as MongoDBCollectionCreateUpdateParameters
|
||||||
);
|
);
|
||||||
|
return updateResponse && (updateResponse.properties.resource as Collection);
|
||||||
return updateResponse && (updateResponse.properties.resource as MongoDBCollectionResource);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -157,7 +154,7 @@ async function updateCassandraTable(
|
|||||||
subscriptionId: string,
|
subscriptionId: string,
|
||||||
resourceGroup: string,
|
resourceGroup: string,
|
||||||
accountName: string,
|
accountName: string,
|
||||||
newCollection: Collection
|
newCollection: Partial<Collection>
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const getResponse = await getCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
const getResponse = await getCassandraTable(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
@@ -184,7 +181,7 @@ async function updateGremlinGraph(
|
|||||||
subscriptionId: string,
|
subscriptionId: string,
|
||||||
resourceGroup: string,
|
resourceGroup: string,
|
||||||
accountName: string,
|
accountName: string,
|
||||||
newCollection: Collection
|
newCollection: Partial<Collection>
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const getResponse = await getGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
const getResponse = await getGremlinGraph(subscriptionId, resourceGroup, accountName, databaseId, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
@@ -208,7 +205,7 @@ async function updateTable(
|
|||||||
subscriptionId: string,
|
subscriptionId: string,
|
||||||
resourceGroup: string,
|
resourceGroup: string,
|
||||||
accountName: string,
|
accountName: string,
|
||||||
newCollection: Collection
|
newCollection: Partial<Collection>
|
||||||
): Promise<Collection> {
|
): Promise<Collection> {
|
||||||
const getResponse = await getTable(subscriptionId, resourceGroup, accountName, collectionId);
|
const getResponse = await getTable(subscriptionId, resourceGroup, accountName, collectionId);
|
||||||
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
if (getResponse && getResponse.properties && getResponse.properties.resource) {
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ ko.components.register("graph-new-vertex-pane", new PaneComponents.GraphNewVerte
|
|||||||
ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent());
|
ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent());
|
||||||
ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
|
ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
|
||||||
ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
|
ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
|
||||||
ko.components.register("table-query-select-pane", new PaneComponents.TableQuerySelectPaneComponent());
|
|
||||||
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
||||||
ko.components.register("string-input-pane", new PaneComponents.StringInputPaneComponent());
|
ko.components.register("string-input-pane", new PaneComponents.StringInputPaneComponent());
|
||||||
ko.components.register("setup-notebooks-pane", new PaneComponents.SetupNotebooksPaneComponent());
|
ko.components.register("setup-notebooks-pane", new PaneComponents.SetupNotebooksPaneComponent());
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
import ko from "knockout";
|
import ko from "knockout";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { updateCollection, updateMongoDBCollectionThroughRP } from "../../../Common/dataAccess/updateCollection";
|
import { updateCollection } from "../../../Common/dataAccess/updateCollection";
|
||||||
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
||||||
import * as DataModels from "../../../Contracts/DataModels";
|
import * as DataModels from "../../../Contracts/DataModels";
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
import { MongoDBCollectionResource } from "../../../Utils/arm/generatedClients/2020-04-01/types";
|
|
||||||
import Explorer from "../../Explorer";
|
import Explorer from "../../Explorer";
|
||||||
import { CollectionSettingsTabV2 } from "../../Tabs/SettingsTabV2";
|
import { CollectionSettingsTabV2 } from "../../Tabs/SettingsTabV2";
|
||||||
import { SettingsComponent, SettingsComponentProps, SettingsComponentState } from "./SettingsComponent";
|
import { SettingsComponent, SettingsComponentProps, SettingsComponentState } from "./SettingsComponent";
|
||||||
@@ -23,13 +22,8 @@ jest.mock("../../../Common/dataAccess/updateCollection", () => ({
|
|||||||
changeFeedPolicy: undefined,
|
changeFeedPolicy: undefined,
|
||||||
analyticalStorageTtl: undefined,
|
analyticalStorageTtl: undefined,
|
||||||
geospatialConfig: undefined,
|
geospatialConfig: undefined,
|
||||||
} as DataModels.Collection),
|
|
||||||
updateMongoDBCollectionThroughRP: jest.fn().mockReturnValue({
|
|
||||||
id: undefined,
|
|
||||||
shardKey: undefined,
|
|
||||||
indexes: [],
|
indexes: [],
|
||||||
analyticalStorageTtl: undefined,
|
}),
|
||||||
} as MongoDBCollectionResource),
|
|
||||||
}));
|
}));
|
||||||
jest.mock("../../../Common/dataAccess/updateOffer", () => ({
|
jest.mock("../../../Common/dataAccess/updateOffer", () => ({
|
||||||
updateOffer: jest.fn().mockReturnValue({} as DataModels.Offer),
|
updateOffer: jest.fn().mockReturnValue({} as DataModels.Offer),
|
||||||
@@ -193,7 +187,6 @@ describe("SettingsComponent", () => {
|
|||||||
};
|
};
|
||||||
await settingsComponentInstance.onSaveClick();
|
await settingsComponentInstance.onSaveClick();
|
||||||
expect(updateCollection).toBeCalled();
|
expect(updateCollection).toBeCalled();
|
||||||
expect(updateMongoDBCollectionThroughRP).toBeCalled();
|
|
||||||
expect(updateOffer).toBeCalled();
|
expect(updateOffer).toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { AuthType } from "../../../AuthType";
|
|||||||
import * as Constants from "../../../Common/Constants";
|
import * as Constants from "../../../Common/Constants";
|
||||||
import { getIndexTransformationProgress } from "../../../Common/dataAccess/getIndexTransformationProgress";
|
import { getIndexTransformationProgress } from "../../../Common/dataAccess/getIndexTransformationProgress";
|
||||||
import { readMongoDBCollectionThroughRP } from "../../../Common/dataAccess/readMongoDBCollection";
|
import { readMongoDBCollectionThroughRP } from "../../../Common/dataAccess/readMongoDBCollection";
|
||||||
import { updateCollection, updateMongoDBCollectionThroughRP } from "../../../Common/dataAccess/updateCollection";
|
import { updateCollection } from "../../../Common/dataAccess/updateCollection";
|
||||||
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
|
||||||
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
|
||||||
import * as DataModels from "../../../Contracts/DataModels";
|
import * as DataModels from "../../../Contracts/DataModels";
|
||||||
@@ -782,12 +782,12 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
if (this.state.isMongoIndexingPolicySaveable && this.mongoDBCollectionResource) {
|
if (this.state.isMongoIndexingPolicySaveable && this.mongoDBCollectionResource) {
|
||||||
try {
|
try {
|
||||||
const newMongoIndexes = this.getMongoIndexesToSave();
|
const newMongoIndexes = this.getMongoIndexesToSave();
|
||||||
const newMongoCollection: MongoDBCollectionResource = {
|
const newMongoCollection = {
|
||||||
...this.mongoDBCollectionResource,
|
...this.mongoDBCollectionResource,
|
||||||
indexes: newMongoIndexes,
|
indexes: newMongoIndexes,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.mongoDBCollectionResource = await updateMongoDBCollectionThroughRP(
|
this.mongoDBCollectionResource = await updateCollection(
|
||||||
this.collection.databaseId,
|
this.collection.databaseId,
|
||||||
this.collection.id(),
|
this.collection.id(),
|
||||||
newMongoCollection
|
newMongoCollection
|
||||||
|
|||||||
@@ -262,27 +262,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
NewVertexPane {
|
NewVertexPane {
|
||||||
"buildString": [Function],
|
"buildString": [Function],
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
@@ -740,27 +719,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"querySelectPane": QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"refreshDatabaseAccount": [Function],
|
"refreshDatabaseAccount": [Function],
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
@@ -1099,27 +1057,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
NewVertexPane {
|
NewVertexPane {
|
||||||
"buildString": [Function],
|
"buildString": [Function],
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
@@ -1577,27 +1514,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"querySelectPane": QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"refreshDatabaseAccount": [Function],
|
"refreshDatabaseAccount": [Function],
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
@@ -1949,27 +1865,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
NewVertexPane {
|
NewVertexPane {
|
||||||
"buildString": [Function],
|
"buildString": [Function],
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
@@ -2427,27 +2322,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"querySelectPane": QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"refreshDatabaseAccount": [Function],
|
"refreshDatabaseAccount": [Function],
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
@@ -2786,27 +2660,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
NewVertexPane {
|
NewVertexPane {
|
||||||
"buildString": [Function],
|
"buildString": [Function],
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
@@ -3264,27 +3117,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"querySelectPane": QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"refreshDatabaseAccount": [Function],
|
"refreshDatabaseAccount": [Function],
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
|
|||||||
@@ -65,9 +65,10 @@ import { SetupNotebooksPane } from "./Panes/SetupNotebooksPane";
|
|||||||
import { StringInputPane } from "./Panes/StringInputPane";
|
import { StringInputPane } from "./Panes/StringInputPane";
|
||||||
import AddTableEntityPane from "./Panes/Tables/AddTableEntityPane";
|
import AddTableEntityPane from "./Panes/Tables/AddTableEntityPane";
|
||||||
import EditTableEntityPane from "./Panes/Tables/EditTableEntityPane";
|
import EditTableEntityPane from "./Panes/Tables/EditTableEntityPane";
|
||||||
import { QuerySelectPane } from "./Panes/Tables/QuerySelectPane";
|
import { TableQuerySelectPanel } from "./Panes/Tables/TableQuerySelectPanel";
|
||||||
import { UploadFilePane } from "./Panes/UploadFilePane";
|
import { UploadFilePane } from "./Panes/UploadFilePane";
|
||||||
import { UploadItemsPane } from "./Panes/UploadItemsPane";
|
import { UploadItemsPane } from "./Panes/UploadItemsPane";
|
||||||
|
import QueryViewModel from "./Tables/QueryBuilder/QueryViewModel";
|
||||||
import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient";
|
import { CassandraAPIDataClient, TableDataClient, TablesAPIDataClient } from "./Tables/TableDataClient";
|
||||||
import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab";
|
import NotebookV2Tab, { NotebookTabOptions } from "./Tabs/NotebookV2Tab";
|
||||||
import TabsBase from "./Tabs/TabsBase";
|
import TabsBase from "./Tabs/TabsBase";
|
||||||
@@ -195,7 +196,6 @@ export default class Explorer {
|
|||||||
public graphStylingPane: GraphStylingPane;
|
public graphStylingPane: GraphStylingPane;
|
||||||
public addTableEntityPane: AddTableEntityPane;
|
public addTableEntityPane: AddTableEntityPane;
|
||||||
public editTableEntityPane: EditTableEntityPane;
|
public editTableEntityPane: EditTableEntityPane;
|
||||||
public querySelectPane: QuerySelectPane;
|
|
||||||
public newVertexPane: NewVertexPane;
|
public newVertexPane: NewVertexPane;
|
||||||
public cassandraAddCollectionPane: CassandraAddCollectionPane;
|
public cassandraAddCollectionPane: CassandraAddCollectionPane;
|
||||||
public stringInputPane: StringInputPane;
|
public stringInputPane: StringInputPane;
|
||||||
@@ -566,13 +566,6 @@ export default class Explorer {
|
|||||||
container: this,
|
container: this,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.querySelectPane = new QuerySelectPane({
|
|
||||||
id: "queryselectpane",
|
|
||||||
visible: ko.observable<boolean>(false),
|
|
||||||
|
|
||||||
container: this,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.newVertexPane = new NewVertexPane({
|
this.newVertexPane = new NewVertexPane({
|
||||||
id: "newvertexpane",
|
id: "newvertexpane",
|
||||||
visible: ko.observable<boolean>(false),
|
visible: ko.observable<boolean>(false),
|
||||||
@@ -610,7 +603,6 @@ export default class Explorer {
|
|||||||
this.graphStylingPane,
|
this.graphStylingPane,
|
||||||
this.addTableEntityPane,
|
this.addTableEntityPane,
|
||||||
this.editTableEntityPane,
|
this.editTableEntityPane,
|
||||||
this.querySelectPane,
|
|
||||||
this.newVertexPane,
|
this.newVertexPane,
|
||||||
this.cassandraAddCollectionPane,
|
this.cassandraAddCollectionPane,
|
||||||
this.stringInputPane,
|
this.stringInputPane,
|
||||||
@@ -2361,4 +2353,11 @@ export default class Explorer {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public openTableSelectQueryPanel(queryViewModal: QueryViewModel): void {
|
||||||
|
this.openSidePanel(
|
||||||
|
"Select Column",
|
||||||
|
<TableQuerySelectPanel explorer={this} closePanel={this.closeSidePanel} queryViewModel={queryViewModal} />
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { NeighborVertexBasicInfo } from "./GraphExplorer";
|
|
||||||
import * as GraphData from "./GraphData";
|
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
|
import * as GraphData from "./GraphData";
|
||||||
|
import { NeighborVertexBasicInfo } from "./GraphExplorer";
|
||||||
|
|
||||||
interface JoinArrayMaxCharOutput {
|
interface JoinArrayMaxCharOutput {
|
||||||
result: string; // string output
|
result: string; // string output
|
||||||
@@ -13,9 +13,9 @@ interface EdgePropertyType {
|
|||||||
inV?: string;
|
inV?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNeighborTitle(neighbor: NeighborVertexBasicInfo): string {
|
export const getNeighborTitle = (neighbor: NeighborVertexBasicInfo): string => {
|
||||||
return `edge id: ${neighbor.edgeId}, vertex id: ${neighbor.id}`;
|
return `edge id: ${neighbor.edgeId}, vertex id: ${neighbor.id}`;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Collect all edges from this node
|
* Collect all edges from this node
|
||||||
@@ -23,11 +23,11 @@ export function getNeighborTitle(neighbor: NeighborVertexBasicInfo): string {
|
|||||||
* @param graphData
|
* @param graphData
|
||||||
* @param newNodes (optional) object describing new nodes encountered
|
* @param newNodes (optional) object describing new nodes encountered
|
||||||
*/
|
*/
|
||||||
export function createEdgesfromNode(
|
export const createEdgesfromNode = (
|
||||||
vertex: GraphData.GremlinVertex,
|
vertex: GraphData.GremlinVertex,
|
||||||
graphData: GraphData.GraphData<GraphData.GremlinVertex, GraphData.GremlinEdge>,
|
graphData: GraphData.GraphData<GraphData.GremlinVertex, GraphData.GremlinEdge>,
|
||||||
newNodes?: { [id: string]: boolean }
|
newNodes?: { [id: string]: boolean }
|
||||||
): void {
|
): void => {
|
||||||
if (Object.prototype.hasOwnProperty.call(vertex, "outE")) {
|
if (Object.prototype.hasOwnProperty.call(vertex, "outE")) {
|
||||||
const outE = vertex.outE;
|
const outE = vertex.outE;
|
||||||
for (const label in outE) {
|
for (const label in outE) {
|
||||||
@@ -66,7 +66,7 @@ export function createEdgesfromNode(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From ['id1', 'id2', 'idn'] build the following string "'id1','id2','idn'".
|
* From ['id1', 'id2', 'idn'] build the following string "'id1','id2','idn'".
|
||||||
@@ -75,7 +75,7 @@ export function createEdgesfromNode(
|
|||||||
* @param maxSize
|
* @param maxSize
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
export function getLimitedArrayString(array: string[], maxSize: number): JoinArrayMaxCharOutput {
|
export const getLimitedArrayString = (array: string[], maxSize: number): JoinArrayMaxCharOutput => {
|
||||||
if (!array || array.length === 0 || array[0].length + 2 > maxSize) {
|
if (!array || array.length === 0 || array[0].length + 2 > maxSize) {
|
||||||
return { result: "", consumedCount: 0 };
|
return { result: "", consumedCount: 0 };
|
||||||
}
|
}
|
||||||
@@ -96,16 +96,16 @@ export function getLimitedArrayString(array: string[], maxSize: number): JoinArr
|
|||||||
result: output,
|
result: output,
|
||||||
consumedCount: i + 1,
|
consumedCount: i + 1,
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export function createFetchEdgePairQuery(
|
export const createFetchEdgePairQuery = (
|
||||||
outE: boolean,
|
outE: boolean,
|
||||||
pkid: string,
|
pkid: string,
|
||||||
excludedEdgeIds: string[],
|
excludedEdgeIds: string[],
|
||||||
startIndex: number,
|
startIndex: number,
|
||||||
pageSize: number,
|
pageSize: number,
|
||||||
withoutStepArgMaxLenght: number
|
withoutStepArgMaxLenght: number
|
||||||
): string {
|
): string => {
|
||||||
let gremlinQuery: string;
|
let gremlinQuery: string;
|
||||||
if (excludedEdgeIds.length > 0) {
|
if (excludedEdgeIds.length > 0) {
|
||||||
// build a string up to max char
|
// build a string up to max char
|
||||||
@@ -128,15 +128,15 @@ export function createFetchEdgePairQuery(
|
|||||||
}().as('v').select('e', 'v')`;
|
}().as('v').select('e', 'v')`;
|
||||||
}
|
}
|
||||||
return gremlinQuery;
|
return gremlinQuery;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trim graph
|
* Trim graph
|
||||||
*/
|
*/
|
||||||
export function trimGraph(
|
export const trimGraph = (
|
||||||
currentRoot: GraphData.GremlinVertex,
|
currentRoot: GraphData.GremlinVertex,
|
||||||
graphData: GraphData.GraphData<GraphData.GremlinVertex, GraphData.GremlinEdge>
|
graphData: GraphData.GraphData<GraphData.GremlinVertex, GraphData.GremlinEdge>
|
||||||
): void {
|
): void => {
|
||||||
const importantNodes = [currentRoot.id].concat(currentRoot._ancestorsId);
|
const importantNodes = [currentRoot.id].concat(currentRoot._ancestorsId);
|
||||||
graphData.unloadAllVertices(importantNodes);
|
graphData.unloadAllVertices(importantNodes);
|
||||||
|
|
||||||
@@ -144,32 +144,32 @@ export function trimGraph(
|
|||||||
$.each(graphData.ids, (index: number, id: string) => {
|
$.each(graphData.ids, (index: number, id: string) => {
|
||||||
graphData.getVertexById(id)._isFixedPosition = importantNodes.indexOf(id) !== -1;
|
graphData.getVertexById(id)._isFixedPosition = importantNodes.indexOf(id) !== -1;
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
export function addRootChildToGraph(
|
export const addRootChildToGraph = (
|
||||||
root: GraphData.GremlinVertex,
|
root: GraphData.GremlinVertex,
|
||||||
child: GraphData.GremlinVertex,
|
child: GraphData.GremlinVertex,
|
||||||
graphData: GraphData.GraphData<GraphData.GremlinVertex, GraphData.GremlinEdge>
|
graphData: GraphData.GraphData<GraphData.GremlinVertex, GraphData.GremlinEdge>
|
||||||
): void {
|
): void => {
|
||||||
child._ancestorsId = (root._ancestorsId || []).concat([root.id]);
|
child._ancestorsId = (root._ancestorsId || []).concat([root.id]);
|
||||||
graphData.addVertex(child);
|
graphData.addVertex(child);
|
||||||
createEdgesfromNode(child, graphData);
|
createEdgesfromNode(child, graphData);
|
||||||
graphData.addNeighborInfo(child);
|
graphData.addNeighborInfo(child);
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Perform minimal substitution to prevent breaking gremlin query and allow \"" for now.
|
* TODO Perform minimal substitution to prevent breaking gremlin query and allow \"" for now.
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
export function escapeDoubleQuotes(value: string): string {
|
export const escapeDoubleQuotes = (value: string): string => {
|
||||||
return value === undefined ? value : value.replace(/"/g, '\\"');
|
return value === undefined ? value : value.replace(/"/g, '\\"');
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Surround with double-quotes if val is a string.
|
* Surround with double-quotes if val is a string.
|
||||||
* @param val
|
* @param val
|
||||||
*/
|
*/
|
||||||
export function getQuotedPropValue(ip: ViewModels.InputPropertyValue): string {
|
export const getQuotedPropValue = (ip: ViewModels.InputPropertyValue): string => {
|
||||||
switch (ip.type) {
|
switch (ip.type) {
|
||||||
case "number":
|
case "number":
|
||||||
case "boolean":
|
case "boolean":
|
||||||
@@ -179,12 +179,12 @@ export function getQuotedPropValue(ip: ViewModels.InputPropertyValue): string {
|
|||||||
default:
|
default:
|
||||||
return `"${escapeDoubleQuotes(ip.value as string)}"`;
|
return `"${escapeDoubleQuotes(ip.value as string)}"`;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Perform minimal substitution to prevent breaking gremlin query and allow \' for now.
|
* TODO Perform minimal substitution to prevent breaking gremlin query and allow \' for now.
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
export function escapeSingleQuotes(value: string): string {
|
export const escapeSingleQuotes = (value: string): string => {
|
||||||
return value === undefined ? value : value.replace(/'/g, "\\'");
|
return value === undefined ? value : value.replace(/'/g, "\\'");
|
||||||
}
|
};
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
|
||||||
import { shallow } from "enzyme";
|
import { shallow } from "enzyme";
|
||||||
|
import React from "react";
|
||||||
import {
|
import {
|
||||||
NotificationConsoleComponentProps,
|
|
||||||
NotificationConsoleComponent,
|
|
||||||
ConsoleDataType,
|
ConsoleDataType,
|
||||||
|
NotificationConsoleComponent,
|
||||||
|
NotificationConsoleComponentProps,
|
||||||
} from "./NotificationConsoleComponent";
|
} from "./NotificationConsoleComponent";
|
||||||
|
|
||||||
describe("NotificationConsoleComponent", () => {
|
describe("NotificationConsoleComponent", () => {
|
||||||
@@ -12,7 +12,7 @@ describe("NotificationConsoleComponent", () => {
|
|||||||
consoleData: undefined,
|
consoleData: undefined,
|
||||||
isConsoleExpanded: false,
|
isConsoleExpanded: false,
|
||||||
inProgressConsoleDataIdToBeDeleted: "",
|
inProgressConsoleDataIdToBeDeleted: "",
|
||||||
setIsConsoleExpanded: (isExpanded: boolean): void => {},
|
setIsConsoleExpanded: (): void => undefined,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ describe("NotificationConsoleComponent", () => {
|
|||||||
wrapper.setProps(props);
|
wrapper.setProps(props);
|
||||||
expect(wrapper.find(".notificationConsoleData .date").text()).toEqual(date);
|
expect(wrapper.find(".notificationConsoleData .date").text()).toEqual(date);
|
||||||
expect(wrapper.find(".notificationConsoleData .message").text()).toEqual(message);
|
expect(wrapper.find(".notificationConsoleData .message").text()).toEqual(message);
|
||||||
expect(wrapper.exists(`.notificationConsoleData .${iconClassName}`));
|
expect(wrapper.exists(`.notificationConsoleData .${iconClassName}`)).toBe(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
it("renders progress notifications", () => {
|
it("renders progress notifications", () => {
|
||||||
@@ -139,7 +139,7 @@ describe("NotificationConsoleComponent", () => {
|
|||||||
wrapper.setProps(props);
|
wrapper.setProps(props);
|
||||||
|
|
||||||
wrapper.find(".clearNotificationsButton").simulate("click");
|
wrapper.find(".clearNotificationsButton").simulate("click");
|
||||||
expect(!wrapper.exists(".notificationConsoleData"));
|
expect(wrapper.exists(".notificationConsoleData")).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("collapses and hide content", () => {
|
it("collapses and hide content", () => {
|
||||||
@@ -155,7 +155,7 @@ describe("NotificationConsoleComponent", () => {
|
|||||||
wrapper.setProps(props);
|
wrapper.setProps(props);
|
||||||
|
|
||||||
wrapper.find(".notificationConsoleHeader").simulate("click");
|
wrapper.find(".notificationConsoleHeader").simulate("click");
|
||||||
expect(!wrapper.exists(".notificationConsoleContent"));
|
expect(wrapper.exists(".notificationConsoleContent")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("display latest data in header", () => {
|
it("display latest data in header", () => {
|
||||||
|
|||||||
@@ -2,19 +2,20 @@
|
|||||||
* React component for control bar
|
* React component for control bar
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from "react";
|
|
||||||
import { ClientDefaults, KeyCodes } from "../../../Common/Constants";
|
|
||||||
import AnimateHeight from "react-animate-height";
|
|
||||||
import { Dropdown, IDropdownOption } from "office-ui-fabric-react";
|
import { Dropdown, IDropdownOption } from "office-ui-fabric-react";
|
||||||
import LoadingIcon from "../../../../images/loading.svg";
|
import * as React from "react";
|
||||||
|
import AnimateHeight from "react-animate-height";
|
||||||
|
import LoaderIcon from "../../../../images/circular_loader_black_16x16.gif";
|
||||||
|
import ClearIcon from "../../../../images/Clear.svg";
|
||||||
import ErrorBlackIcon from "../../../../images/error_black.svg";
|
import ErrorBlackIcon from "../../../../images/error_black.svg";
|
||||||
|
import ErrorRedIcon from "../../../../images/error_red.svg";
|
||||||
import infoBubbleIcon from "../../../../images/info-bubble-9x9.svg";
|
import infoBubbleIcon from "../../../../images/info-bubble-9x9.svg";
|
||||||
import InfoIcon from "../../../../images/info_color.svg";
|
import InfoIcon from "../../../../images/info_color.svg";
|
||||||
import ErrorRedIcon from "../../../../images/error_red.svg";
|
import LoadingIcon from "../../../../images/loading.svg";
|
||||||
import ClearIcon from "../../../../images/Clear.svg";
|
|
||||||
import LoaderIcon from "../../../../images/circular_loader_black_16x16.gif";
|
|
||||||
import ChevronUpIcon from "../../../../images/QueryBuilder/CollapseChevronUp_16x.png";
|
|
||||||
import ChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
|
import ChevronDownIcon from "../../../../images/QueryBuilder/CollapseChevronDown_16x.png";
|
||||||
|
import ChevronUpIcon from "../../../../images/QueryBuilder/CollapseChevronUp_16x.png";
|
||||||
|
import { ClientDefaults, KeyCodes } from "../../../Common/Constants";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log levels
|
* Log levels
|
||||||
@@ -76,7 +77,7 @@ export class NotificationConsoleComponent extends React.Component<
|
|||||||
public componentDidUpdate(
|
public componentDidUpdate(
|
||||||
prevProps: NotificationConsoleComponentProps,
|
prevProps: NotificationConsoleComponentProps,
|
||||||
prevState: NotificationConsoleComponentState
|
prevState: NotificationConsoleComponentState
|
||||||
) {
|
): void {
|
||||||
const currentHeaderStatus = NotificationConsoleComponent.extractHeaderStatus(this.props.consoleData);
|
const currentHeaderStatus = NotificationConsoleComponent.extractHeaderStatus(this.props.consoleData);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -97,7 +98,7 @@ export class NotificationConsoleComponent extends React.Component<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public setElememntRef = (element: HTMLElement) => {
|
public setElememntRef = (element: HTMLElement): void => {
|
||||||
this.consoleHeaderElement = element;
|
this.consoleHeaderElement = element;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -116,7 +117,7 @@ export class NotificationConsoleComponent extends React.Component<
|
|||||||
className="notificationConsoleHeader"
|
className="notificationConsoleHeader"
|
||||||
id="notificationConsoleHeader"
|
id="notificationConsoleHeader"
|
||||||
ref={this.setElememntRef}
|
ref={this.setElememntRef}
|
||||||
onClick={(event: React.MouseEvent<HTMLDivElement>) => this.expandCollapseConsole()}
|
onClick={() => this.expandCollapseConsole()}
|
||||||
onKeyDown={(event: React.KeyboardEvent<HTMLDivElement>) => this.onExpandCollapseKeyPress(event)}
|
onKeyDown={(event: React.KeyboardEvent<HTMLDivElement>) => this.onExpandCollapseKeyPress(event)}
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
>
|
>
|
||||||
@@ -135,6 +136,7 @@ export class NotificationConsoleComponent extends React.Component<
|
|||||||
<span className="numInfoItems">{numInfoItems}</span>
|
<span className="numInfoItems">{numInfoItems}</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
{userContext.features.pr && <PrPreview pr={userContext.features.pr} />}
|
||||||
<span className="consoleSplitter" />
|
<span className="consoleSplitter" />
|
||||||
<span className="headerStatus">
|
<span className="headerStatus">
|
||||||
<span className="headerStatusEllipsis">{this.state.headerStatus}</span>
|
<span className="headerStatusEllipsis">{this.state.headerStatus}</span>
|
||||||
@@ -304,3 +306,18 @@ export class NotificationConsoleComponent extends React.Component<
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PrPreview = (props: { pr: string }) => {
|
||||||
|
const url = new URL(props.pr);
|
||||||
|
const [, ref] = url.hash.split("#");
|
||||||
|
url.hash = "";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span className="consoleSplitter" />
|
||||||
|
<a target="_blank" rel="noreferrer" href={url.href} style={{ marginRight: "1em", fontWeight: "bold" }}>
|
||||||
|
{ref}
|
||||||
|
</a>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
// Manages all the redux logic for the notebook nteract code
|
// Manages all the redux logic for the notebook nteract code
|
||||||
// TODO: Merge with NotebookClient?
|
// TODO: Merge with NotebookClient?
|
||||||
import { NotebookWorkspaceConnectionInfo } from "../../Contracts/DataModels";
|
|
||||||
import * as Constants from "../../Common/Constants";
|
|
||||||
import { CdbAppState, makeCdbRecord } from "./NotebookComponent/types";
|
|
||||||
|
|
||||||
// Vendor modules
|
// Vendor modules
|
||||||
import {
|
import {
|
||||||
actions,
|
actions,
|
||||||
AppState,
|
AppState,
|
||||||
|
ContentRecord,
|
||||||
createHostRef,
|
createHostRef,
|
||||||
createKernelspecsRef,
|
createKernelspecsRef,
|
||||||
|
HostRecord,
|
||||||
|
HostRef,
|
||||||
|
IContentProvider,
|
||||||
|
KernelspecsRef,
|
||||||
makeAppRecord,
|
makeAppRecord,
|
||||||
makeCommsRecord,
|
makeCommsRecord,
|
||||||
makeContentsRecord,
|
makeContentsRecord,
|
||||||
@@ -19,23 +20,21 @@ import {
|
|||||||
makeJupyterHostRecord,
|
makeJupyterHostRecord,
|
||||||
makeStateRecord,
|
makeStateRecord,
|
||||||
makeTransformsRecord,
|
makeTransformsRecord,
|
||||||
ContentRecord,
|
|
||||||
HostRecord,
|
|
||||||
HostRef,
|
|
||||||
KernelspecsRef,
|
|
||||||
IContentProvider,
|
|
||||||
} from "@nteract/core";
|
} from "@nteract/core";
|
||||||
|
import { configOption, createConfigCollection, defineConfigOption } from "@nteract/mythic-configuration";
|
||||||
import { Media } from "@nteract/outputs";
|
import { Media } from "@nteract/outputs";
|
||||||
import TransformVDOM from "@nteract/transform-vdom";
|
import TransformVDOM from "@nteract/transform-vdom";
|
||||||
import * as Immutable from "immutable";
|
import * as Immutable from "immutable";
|
||||||
import { Store, AnyAction, MiddlewareAPI, Middleware, Dispatch } from "redux";
|
|
||||||
|
|
||||||
import configureStore from "./NotebookComponent/store";
|
|
||||||
|
|
||||||
import { Notification } from "react-notification-system";
|
import { Notification } from "react-notification-system";
|
||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import { AnyAction, Dispatch, Middleware, MiddlewareAPI, Store } from "redux";
|
||||||
|
import * as Constants from "../../Common/Constants";
|
||||||
|
import { NotebookWorkspaceConnectionInfo } from "../../Contracts/DataModels";
|
||||||
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
||||||
import { configOption, createConfigCollection, defineConfigOption } from "@nteract/mythic-configuration";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
|
import { userContext } from "../../UserContext";
|
||||||
|
import configureStore from "./NotebookComponent/store";
|
||||||
|
import { CdbAppState, makeCdbRecord } from "./NotebookComponent/types";
|
||||||
|
import JavaScript from "./NotebookRenderer/outputs/javascript";
|
||||||
|
|
||||||
export type KernelSpecsDisplay = { name: string; displayName: string };
|
export type KernelSpecsDisplay = { name: string; displayName: string };
|
||||||
|
|
||||||
@@ -168,7 +167,7 @@ export class NotebookClientV2 {
|
|||||||
"application/vnd.vega.v5+json": NullTransform,
|
"application/vnd.vega.v5+json": NullTransform,
|
||||||
"application/vdom.v1+json": TransformVDOM,
|
"application/vdom.v1+json": TransformVDOM,
|
||||||
"application/json": Media.Json,
|
"application/json": Media.Json,
|
||||||
"application/javascript": Media.JavaScript,
|
"application/javascript": userContext.features.sandboxNotebookOutputs ? JavaScript : Media.JavaScript,
|
||||||
"text/html": Media.HTML,
|
"text/html": Media.HTML,
|
||||||
"text/markdown": Media.Markdown,
|
"text/markdown": Media.Markdown,
|
||||||
"text/latex": Media.LaTeX,
|
"text/latex": Media.LaTeX,
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
import * as React from "react";
|
|
||||||
import "./base.css";
|
|
||||||
import "./default.css";
|
|
||||||
|
|
||||||
import { CodeCell, RawCell, Cells, MarkdownCell } from "@nteract/stateful-components";
|
|
||||||
import Prompt, { PassedPromptProps } from "@nteract/stateful-components/lib/inputs/prompt";
|
|
||||||
import { AzureTheme } from "./AzureTheme";
|
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { Dispatch } from "redux";
|
|
||||||
import { actions, ContentRef } from "@nteract/core";
|
import { actions, ContentRef } from "@nteract/core";
|
||||||
import loadTransform from "../NotebookComponent/loadTransform";
|
import { KernelOutputError, StreamText } from "@nteract/outputs";
|
||||||
|
import { Cells, CodeCell, MarkdownCell, RawCell } from "@nteract/stateful-components";
|
||||||
import MonacoEditor from "@nteract/stateful-components/lib/inputs/connected-editors/monacoEditor";
|
import MonacoEditor from "@nteract/stateful-components/lib/inputs/connected-editors/monacoEditor";
|
||||||
import { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor";
|
import { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor";
|
||||||
|
import Prompt, { PassedPromptProps } from "@nteract/stateful-components/lib/inputs/prompt";
|
||||||
|
import TransformMedia from "@nteract/stateful-components/lib/outputs/transform-media";
|
||||||
|
import * as React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { Dispatch } from "redux";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
|
import loadTransform from "../NotebookComponent/loadTransform";
|
||||||
|
import { AzureTheme } from "./AzureTheme";
|
||||||
|
import "./base.css";
|
||||||
|
import "./default.css";
|
||||||
import "./NotebookReadOnlyRenderer.less";
|
import "./NotebookReadOnlyRenderer.less";
|
||||||
|
import IFrameOutputs from "./outputs/IFrameOutputs";
|
||||||
|
|
||||||
export interface NotebookRendererProps {
|
export interface NotebookRendererProps {
|
||||||
contentRef: any;
|
contentRef: any;
|
||||||
@@ -60,6 +62,16 @@ class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
|||||||
<CodeCell id={id} contentRef={contentRef}>
|
<CodeCell id={id} contentRef={contentRef}>
|
||||||
{{
|
{{
|
||||||
prompt: (props: { id: string; contentRef: string }) => this.renderPrompt(props.id, props.contentRef),
|
prompt: (props: { id: string; contentRef: string }) => this.renderPrompt(props.id, props.contentRef),
|
||||||
|
outputs: userContext.features.sandboxNotebookOutputs
|
||||||
|
? (props: any) => (
|
||||||
|
<IFrameOutputs id={id} contentRef={contentRef}>
|
||||||
|
<TransformMedia output_type={"display_data"} id={id} contentRef={contentRef} />
|
||||||
|
<TransformMedia output_type={"execute_result"} id={id} contentRef={contentRef} />
|
||||||
|
<KernelOutputError />
|
||||||
|
<StreamText />
|
||||||
|
</IFrameOutputs>
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
editor: {
|
editor: {
|
||||||
monaco: (props: PassedEditorProps) =>
|
monaco: (props: PassedEditorProps) =>
|
||||||
this.props.hideInputs ? <></> : <MonacoEditor readOnly={true} {...props} editorType={"monaco"} />,
|
this.props.hideInputs ? <></> : <MonacoEditor readOnly={true} {...props} editorType={"monaco"} />,
|
||||||
|
|||||||
@@ -1,37 +1,32 @@
|
|||||||
import * as React from "react";
|
import { CellId } from "@nteract/commutable";
|
||||||
import "./base.css";
|
import { CellType } from "@nteract/commutable/src";
|
||||||
import "./default.css";
|
import { actions, ContentRef } from "@nteract/core";
|
||||||
|
import { KernelOutputError, StreamText } from "@nteract/outputs";
|
||||||
import { RawCell, Cells, CodeCell, MarkdownCell } from "@nteract/stateful-components";
|
import { Cells, CodeCell, MarkdownCell, RawCell } from "@nteract/stateful-components";
|
||||||
import MonacoEditor from "@nteract/stateful-components/lib/inputs/connected-editors/monacoEditor";
|
import MonacoEditor from "@nteract/stateful-components/lib/inputs/connected-editors/monacoEditor";
|
||||||
import { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor";
|
import { PassedEditorProps } from "@nteract/stateful-components/lib/inputs/editor";
|
||||||
|
import TransformMedia from "@nteract/stateful-components/lib/outputs/transform-media";
|
||||||
import Prompt from "./Prompt";
|
import * as React from "react";
|
||||||
import { promptContent } from "./PromptContent";
|
|
||||||
|
|
||||||
import { AzureTheme } from "./AzureTheme";
|
|
||||||
import { DndProvider } from "react-dnd";
|
import { DndProvider } from "react-dnd";
|
||||||
import HTML5Backend from "react-dnd-html5-backend";
|
import HTML5Backend from "react-dnd-html5-backend";
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Dispatch } from "redux";
|
import { Dispatch } from "redux";
|
||||||
import { actions, ContentRef } from "@nteract/core";
|
import { userContext } from "../../../UserContext";
|
||||||
import { CellId } from "@nteract/commutable";
|
|
||||||
import loadTransform from "../NotebookComponent/loadTransform";
|
|
||||||
import DraggableCell from "./decorators/draggable";
|
|
||||||
import CellCreator from "./decorators/CellCreator";
|
|
||||||
import KeyboardShortcuts from "./decorators/kbd-shortcuts";
|
|
||||||
|
|
||||||
import CellToolbar from "./Toolbar";
|
|
||||||
import StatusBar from "./StatusBar";
|
|
||||||
|
|
||||||
import HijackScroll from "./decorators/hijack-scroll";
|
|
||||||
import { CellType } from "@nteract/commutable/src";
|
|
||||||
|
|
||||||
import "./NotebookRenderer.less";
|
|
||||||
import HoverableCell from "./decorators/HoverableCell";
|
|
||||||
import CellLabeler from "./decorators/CellLabeler";
|
|
||||||
import * as cdbActions from "../NotebookComponent/actions";
|
import * as cdbActions from "../NotebookComponent/actions";
|
||||||
|
import loadTransform from "../NotebookComponent/loadTransform";
|
||||||
|
import { AzureTheme } from "./AzureTheme";
|
||||||
|
import "./base.css";
|
||||||
|
import CellCreator from "./decorators/CellCreator";
|
||||||
|
import CellLabeler from "./decorators/CellLabeler";
|
||||||
|
import HoverableCell from "./decorators/HoverableCell";
|
||||||
|
import KeyboardShortcuts from "./decorators/kbd-shortcuts";
|
||||||
|
import "./default.css";
|
||||||
|
import "./NotebookRenderer.less";
|
||||||
|
import IFrameOutputs from "./outputs/IFrameOutputs";
|
||||||
|
import Prompt from "./Prompt";
|
||||||
|
import { promptContent } from "./PromptContent";
|
||||||
|
import StatusBar from "./StatusBar";
|
||||||
|
import CellToolbar from "./Toolbar";
|
||||||
|
|
||||||
export interface NotebookRendererBaseProps {
|
export interface NotebookRendererBaseProps {
|
||||||
contentRef: any;
|
contentRef: any;
|
||||||
@@ -112,6 +107,16 @@ class BaseNotebookRenderer extends React.Component<NotebookRendererProps> {
|
|||||||
</Prompt>
|
</Prompt>
|
||||||
),
|
),
|
||||||
toolbar: () => <CellToolbar id={id} contentRef={contentRef} />,
|
toolbar: () => <CellToolbar id={id} contentRef={contentRef} />,
|
||||||
|
outputs: userContext.features.sandboxNotebookOutputs
|
||||||
|
? (props: any) => (
|
||||||
|
<IFrameOutputs id={id} contentRef={contentRef}>
|
||||||
|
<TransformMedia output_type={"display_data"} id={id} contentRef={contentRef} />
|
||||||
|
<TransformMedia output_type={"execute_result"} id={id} contentRef={contentRef} />
|
||||||
|
<KernelOutputError />
|
||||||
|
<StreamText />
|
||||||
|
</IFrameOutputs>
|
||||||
|
)
|
||||||
|
: undefined,
|
||||||
}}
|
}}
|
||||||
</CodeCell>
|
</CodeCell>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { AppState, ContentRef, selectors } from "@nteract/core";
|
||||||
|
import { Output } from "@nteract/outputs";
|
||||||
|
import Immutable from "immutable";
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { SandboxFrame } from "./SandboxFrame";
|
||||||
|
|
||||||
|
// Adapted from https://github.com/nteract/nteract/blob/main/packages/stateful-components/src/outputs/index.tsx
|
||||||
|
// to add support for sandboxing using <iframe>
|
||||||
|
|
||||||
|
interface ComponentProps {
|
||||||
|
id: string;
|
||||||
|
contentRef: ContentRef;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StateProps {
|
||||||
|
hidden: boolean;
|
||||||
|
expanded: boolean;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
outputs: Immutable.List<any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class IFrameOutputs extends React.PureComponent<ComponentProps & StateProps> {
|
||||||
|
render(): JSX.Element {
|
||||||
|
const { outputs, children, hidden, expanded } = this.props;
|
||||||
|
return (
|
||||||
|
<SandboxFrame
|
||||||
|
style={{ border: "none", width: "100%" }}
|
||||||
|
sandbox="allow-downloads allow-forms allow-pointer-lock allow-popups allow-same-origin allow-scripts allow-popups-to-escape-sandbox"
|
||||||
|
>
|
||||||
|
<div className={`nteract-cell-outputs ${hidden ? "hidden" : ""} ${expanded ? "expanded" : ""}`}>
|
||||||
|
{outputs.map((output, index) => (
|
||||||
|
<Output output={output} key={index}>
|
||||||
|
{children}
|
||||||
|
</Output>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</SandboxFrame>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const makeMapStateToProps = (
|
||||||
|
initialState: AppState,
|
||||||
|
ownProps: ComponentProps
|
||||||
|
): ((state: AppState) => StateProps) => {
|
||||||
|
const mapStateToProps = (state: AppState): StateProps => {
|
||||||
|
let outputs = Immutable.List();
|
||||||
|
let hidden = false;
|
||||||
|
let expanded = false;
|
||||||
|
|
||||||
|
const { contentRef, id } = ownProps;
|
||||||
|
const model = selectors.model(state, { contentRef });
|
||||||
|
|
||||||
|
if (model && model.type === "notebook") {
|
||||||
|
const cell = selectors.notebook.cellById(model, { id });
|
||||||
|
if (cell) {
|
||||||
|
outputs = cell.get("outputs", Immutable.List());
|
||||||
|
hidden = cell.cell_type === "code" && cell.getIn(["metadata", "jupyter", "outputs_hidden"]);
|
||||||
|
expanded = cell.cell_type === "code" && cell.getIn(["metadata", "collapsed"]) === false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { outputs, hidden, expanded };
|
||||||
|
};
|
||||||
|
return mapStateToProps;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect<StateProps, void, ComponentProps, AppState>(makeMapStateToProps)(IFrameOutputs);
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import { copyStyles } from "../../../../Utils/StyleUtils";
|
||||||
|
|
||||||
|
interface SandboxFrameProps {
|
||||||
|
style: React.CSSProperties;
|
||||||
|
sandbox: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SandboxFrameState {
|
||||||
|
frame: HTMLIFrameElement;
|
||||||
|
frameBody: HTMLElement;
|
||||||
|
frameHeight: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SandboxFrame extends React.PureComponent<SandboxFrameProps, SandboxFrameState> {
|
||||||
|
private resizeObserver: ResizeObserver;
|
||||||
|
|
||||||
|
constructor(props: SandboxFrameProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
frame: undefined,
|
||||||
|
frameBody: undefined,
|
||||||
|
frameHeight: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): JSX.Element {
|
||||||
|
return (
|
||||||
|
<iframe
|
||||||
|
ref={(ele) => this.setState({ frame: ele })}
|
||||||
|
srcDoc={`<!DOCTYPE html>`}
|
||||||
|
onLoad={(event) => this.onFrameLoad(event)}
|
||||||
|
style={this.props.style}
|
||||||
|
sandbox={this.props.sandbox}
|
||||||
|
height={this.state.frameHeight}
|
||||||
|
>
|
||||||
|
{this.state.frameBody && ReactDOM.createPortal(this.props.children, this.state.frameBody)}
|
||||||
|
</iframe>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.resizeObserver?.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
onFrameLoad(event: React.SyntheticEvent<HTMLIFrameElement, Event>): void {
|
||||||
|
const doc = (event.target as HTMLIFrameElement).contentDocument;
|
||||||
|
copyStyles(document, doc);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
frameBody: doc.body,
|
||||||
|
frameHeight: doc.body.scrollHeight,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resizeObserver = new ResizeObserver(() =>
|
||||||
|
this.setState({
|
||||||
|
frameHeight: this.state.frameBody.scrollHeight,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
this.resizeObserver.observe(doc.body);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Media } from "@nteract/outputs";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
/**
|
||||||
|
* The JavaScript code that we would like to execute.
|
||||||
|
*/
|
||||||
|
data: string;
|
||||||
|
/**
|
||||||
|
* The media type associated with our component.
|
||||||
|
*/
|
||||||
|
mediaType: "text/javascript";
|
||||||
|
}
|
||||||
|
|
||||||
|
export class JavaScript extends React.PureComponent<Props> {
|
||||||
|
static defaultProps = {
|
||||||
|
data: "",
|
||||||
|
mediaType: "application/javascript",
|
||||||
|
};
|
||||||
|
|
||||||
|
render(): JSX.Element {
|
||||||
|
return <Media.HTML data={`<script>${this.props.data}</script>`} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JavaScript;
|
||||||
@@ -9,7 +9,6 @@ import SetupNotebooksPaneTemplate from "./SetupNotebooksPane.html";
|
|||||||
import StringInputPaneTemplate from "./StringInputPane.html";
|
import StringInputPaneTemplate from "./StringInputPane.html";
|
||||||
import TableAddEntityPaneTemplate from "./Tables/TableAddEntityPane.html";
|
import TableAddEntityPaneTemplate from "./Tables/TableAddEntityPane.html";
|
||||||
import TableEditEntityPaneTemplate from "./Tables/TableEditEntityPane.html";
|
import TableEditEntityPaneTemplate from "./Tables/TableEditEntityPane.html";
|
||||||
import TableQuerySelectPaneTemplate from "./Tables/TableQuerySelectPane.html";
|
|
||||||
|
|
||||||
export class PaneComponent {
|
export class PaneComponent {
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
@@ -79,16 +78,6 @@ export class TableEditEntityPaneComponent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TableQuerySelectPaneComponent {
|
|
||||||
constructor() {
|
|
||||||
return {
|
|
||||||
viewModel: PaneComponent,
|
|
||||||
template: TableQuerySelectPaneTemplate,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CassandraAddCollectionPaneComponent {
|
export class CassandraAddCollectionPaneComponent {
|
||||||
constructor() {
|
constructor() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -152,3 +152,6 @@
|
|||||||
.removeIcon {
|
.removeIcon {
|
||||||
color: @InfoIconColor;
|
color: @InfoIconColor;
|
||||||
}
|
}
|
||||||
|
.column-select-view {
|
||||||
|
margin: 20px 0px 0px 0px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -238,27 +238,6 @@ exports[`Settings Pane should render Default properly 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
NewVertexPane {
|
NewVertexPane {
|
||||||
"buildString": [Function],
|
"buildString": [Function],
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
@@ -716,27 +695,6 @@ exports[`Settings Pane should render Default properly 1`] = `
|
|||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"querySelectPane": QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"refreshDatabaseAccount": [Function],
|
"refreshDatabaseAccount": [Function],
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
@@ -1163,27 +1121,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
NewVertexPane {
|
NewVertexPane {
|
||||||
"buildString": [Function],
|
"buildString": [Function],
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
@@ -1641,27 +1578,6 @@ exports[`Settings Pane should render Gremlin properly 1`] = `
|
|||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"querySelectPane": QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"refreshDatabaseAccount": [Function],
|
"refreshDatabaseAccount": [Function],
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
|
|||||||
@@ -1,174 +0,0 @@
|
|||||||
import * as ko from "knockout";
|
|
||||||
import _ from "underscore";
|
|
||||||
import * as Constants from "../../Tables/Constants";
|
|
||||||
import QueryViewModel from "../../Tables/QueryBuilder/QueryViewModel";
|
|
||||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
|
||||||
import { ContextualPaneBase } from "../ContextualPaneBase";
|
|
||||||
|
|
||||||
export interface ISelectColumn {
|
|
||||||
columnName: ko.Observable<string>;
|
|
||||||
selected: ko.Observable<boolean>;
|
|
||||||
editable: ko.Observable<boolean>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class QuerySelectPane extends ContextualPaneBase {
|
|
||||||
public titleLabel: string = "Select Columns";
|
|
||||||
public instructionLabel: string = "Select the columns that you want to query.";
|
|
||||||
public availableColumnsTableQueryLabel: string = "Available Columns";
|
|
||||||
public noColumnSelectedWarning: string = "At least one column should be selected.";
|
|
||||||
|
|
||||||
public columnOptions: ko.ObservableArray<ISelectColumn>;
|
|
||||||
public anyColumnSelected: ko.Computed<boolean>;
|
|
||||||
public canSelectAll: ko.Computed<boolean>;
|
|
||||||
public allSelected: ko.Computed<boolean>;
|
|
||||||
|
|
||||||
private selectedColumnOption: ISelectColumn = null;
|
|
||||||
|
|
||||||
public queryViewModel: QueryViewModel;
|
|
||||||
|
|
||||||
constructor(options: ViewModels.PaneOptions) {
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
this.columnOptions = ko.observableArray<ISelectColumn>();
|
|
||||||
this.anyColumnSelected = ko.computed<boolean>(() => {
|
|
||||||
return _.some(this.columnOptions(), (value: ISelectColumn) => {
|
|
||||||
return value.selected();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.canSelectAll = ko.computed<boolean>(() => {
|
|
||||||
return _.some(this.columnOptions(), (value: ISelectColumn) => {
|
|
||||||
return !value.selected();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.allSelected = ko.pureComputed<boolean>({
|
|
||||||
read: () => {
|
|
||||||
return !this.canSelectAll();
|
|
||||||
},
|
|
||||||
write: (value) => {
|
|
||||||
if (value) {
|
|
||||||
this.selectAll();
|
|
||||||
} else {
|
|
||||||
this.clearAll();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
owner: this,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public submit() {
|
|
||||||
this.queryViewModel.selectText(this.getParameters());
|
|
||||||
this.queryViewModel.getSelectMessage();
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public open() {
|
|
||||||
this.setTableColumns(this.queryViewModel.columnOptions());
|
|
||||||
this.setDisplayedColumns(this.queryViewModel.selectText(), this.columnOptions());
|
|
||||||
super.open();
|
|
||||||
}
|
|
||||||
|
|
||||||
private getParameters(): string[] {
|
|
||||||
if (this.canSelectAll() === false) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
var selectedColumns = this.columnOptions().filter((value: ISelectColumn) => value.selected() === true);
|
|
||||||
|
|
||||||
var columns: string[] = selectedColumns.map((value: ISelectColumn) => {
|
|
||||||
var name: string = value.columnName();
|
|
||||||
return name;
|
|
||||||
});
|
|
||||||
|
|
||||||
return columns;
|
|
||||||
}
|
|
||||||
|
|
||||||
public setTableColumns(columnNames: string[]): void {
|
|
||||||
var columns: ISelectColumn[] = columnNames.map((value: string) => {
|
|
||||||
var columnOption: ISelectColumn = {
|
|
||||||
columnName: ko.observable<string>(value),
|
|
||||||
selected: ko.observable<boolean>(true),
|
|
||||||
editable: ko.observable<boolean>(this.isEntityEditable(value)),
|
|
||||||
};
|
|
||||||
return columnOption;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.columnOptions(columns);
|
|
||||||
}
|
|
||||||
|
|
||||||
public setDisplayedColumns(querySelect: string[], columns: ISelectColumn[]): void {
|
|
||||||
if (querySelect == null || _.isEmpty(querySelect)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.setSelected(querySelect, columns);
|
|
||||||
}
|
|
||||||
|
|
||||||
private setSelected(querySelect: string[], columns: ISelectColumn[]): void {
|
|
||||||
this.clearAll();
|
|
||||||
querySelect &&
|
|
||||||
querySelect.forEach((value: string) => {
|
|
||||||
for (var i = 0; i < columns.length; i++) {
|
|
||||||
if (value === columns[i].columnName()) {
|
|
||||||
columns[i].selected(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public availableColumnsCheckboxClick(): boolean {
|
|
||||||
if (this.canSelectAll()) {
|
|
||||||
return this.selectAll();
|
|
||||||
} else {
|
|
||||||
return this.clearAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public selectAll(): boolean {
|
|
||||||
const columnOptions = this.columnOptions && this.columnOptions();
|
|
||||||
columnOptions &&
|
|
||||||
columnOptions.forEach((value: ISelectColumn) => {
|
|
||||||
value.selected(true);
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public clearAll(): boolean {
|
|
||||||
const columnOptions = this.columnOptions && this.columnOptions();
|
|
||||||
columnOptions &&
|
|
||||||
columnOptions.forEach((column: ISelectColumn) => {
|
|
||||||
if (this.isEntityEditable(column.columnName())) {
|
|
||||||
column.selected(false);
|
|
||||||
} else {
|
|
||||||
column.selected(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public handleClick = (data: ISelectColumn, event: KeyboardEvent): boolean => {
|
|
||||||
this.selectTargetItem($(event.currentTarget), data);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
private selectTargetItem($target: JQuery, targetColumn: ISelectColumn): void {
|
|
||||||
this.selectedColumnOption = targetColumn;
|
|
||||||
|
|
||||||
$(".list-item.selected").removeClass("selected");
|
|
||||||
$target.addClass("selected");
|
|
||||||
}
|
|
||||||
|
|
||||||
private isEntityEditable(name: string) {
|
|
||||||
if (this.queryViewModel.queryTablesTab.container.isPreferredApiCassandra()) {
|
|
||||||
const cassandraKeys = this.queryViewModel.queryTablesTab.collection.cassandraKeys.partitionKeys
|
|
||||||
.concat(this.queryViewModel.queryTablesTab.collection.cassandraKeys.clusteringKeys)
|
|
||||||
.map((key) => key.property);
|
|
||||||
return !_.contains<string>(cassandraKeys, name);
|
|
||||||
}
|
|
||||||
return !(
|
|
||||||
name === Constants.EntityKeyNames.PartitionKey ||
|
|
||||||
name === Constants.EntityKeyNames.RowKey ||
|
|
||||||
name === Constants.EntityKeyNames.Timestamp
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<div data-bind="visible: visible">
|
|
||||||
<div
|
|
||||||
class="contextual-pane-out"
|
|
||||||
data-bind="
|
|
||||||
click: cancel,
|
|
||||||
clickBubble: false"
|
|
||||||
></div>
|
|
||||||
<div class="contextual-pane" id="queryselectpane">
|
|
||||||
<!-- Query Select form - Start -->
|
|
||||||
<div class="contextual-pane-in">
|
|
||||||
<form
|
|
||||||
class="paneContentContainer"
|
|
||||||
data-bind="
|
|
||||||
submit: submit"
|
|
||||||
>
|
|
||||||
<!-- Query Select header - Start -->
|
|
||||||
<div class="firstdivbg headerline">
|
|
||||||
Select Column
|
|
||||||
<div
|
|
||||||
class="closeImg"
|
|
||||||
role="button"
|
|
||||||
aria-label="Close pane"
|
|
||||||
tabindex="0"
|
|
||||||
data-bind="
|
|
||||||
click: cancel, event: { keydown: onCloseKeyPress }"
|
|
||||||
>
|
|
||||||
<img src="../../../../images/close-black.svg" title="Close" alt="Close" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Query Select header - End -->
|
|
||||||
<div class="paneMainContent paneContentContainer">
|
|
||||||
<!--<div class="row">
|
|
||||||
<label id="instructionLabel" data-bind="text: instructionLabel"></label>
|
|
||||||
</div>-->
|
|
||||||
<div><span>Select the columns that you want to query.</span></div>
|
|
||||||
<div class="column-options">
|
|
||||||
<div class="columns-border">
|
|
||||||
<input class="all-select-check" type="checkbox" data-bind="checked: allSelected" />
|
|
||||||
<label
|
|
||||||
style="font-weight: 700"
|
|
||||||
id="availableColumnsTableQueryLabel"
|
|
||||||
data-bind="text: availableColumnsTableQueryLabel"
|
|
||||||
></label>
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<section>
|
|
||||||
<ul data-bind="foreach: columnOptions" aria-labelledby="availableColumnsTableQueryLabel" tabindex="0">
|
|
||||||
<!-- ko template: {if: editable} -->
|
|
||||||
<li
|
|
||||||
class="list-item columns-border"
|
|
||||||
data-bind="attr: { title: columnName }, click: $parent.handleClick "
|
|
||||||
>
|
|
||||||
<input type="checkbox" data-bind="attr: { title: columnName }, checked: selected" />
|
|
||||||
<span data-bind="text: columnName"></span>
|
|
||||||
</li>
|
|
||||||
<!--/ko-->
|
|
||||||
<!-- ko template: {ifnot: editable} -->
|
|
||||||
<li class="list-item columns-border" data-bind="attr: { title: columnName } ">
|
|
||||||
<input type="checkbox" disabled data-bind="checked: selected" />
|
|
||||||
<span data-bind="text: columnName"></span>
|
|
||||||
</li>
|
|
||||||
<!--/ko-->
|
|
||||||
</ul>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row-label" data-bind="style: { visibility: anyColumnSelected() ? 'hidden': 'visible' }">
|
|
||||||
<label class="warning" role="alert" aria-atomic="true" data-bind="text: noColumnSelectedWarning"></label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="paneFooter">
|
|
||||||
<div class="leftpanel-okbut"><input type="submit" value="OK" class="btncreatecoll1" /></div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<!-- Query Select form - End -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,38 @@
|
|||||||
|
import { mount } from "enzyme";
|
||||||
|
import * as ko from "knockout";
|
||||||
|
import React from "react";
|
||||||
|
import Explorer from "../../../Explorer";
|
||||||
|
import QueryViewModel from "../../../Tables/QueryBuilder/QueryViewModel";
|
||||||
|
import { TableQuerySelectPanel } from "./index";
|
||||||
|
|
||||||
|
describe("Table query select Panel", () => {
|
||||||
|
const fakeExplorer = {} as Explorer;
|
||||||
|
const fakeQueryViewModal = {} as QueryViewModel;
|
||||||
|
fakeQueryViewModal.columnOptions = ko.observableArray<string>([""]);
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
explorer: fakeExplorer,
|
||||||
|
closePanel: (): void => undefined,
|
||||||
|
queryViewModel: fakeQueryViewModal,
|
||||||
|
};
|
||||||
|
|
||||||
|
it("should render Default properly", () => {
|
||||||
|
const wrapper = mount(<TableQuerySelectPanel {...props} />);
|
||||||
|
expect(wrapper).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should exist availableCheckbox by default", () => {
|
||||||
|
const wrapper = mount(<TableQuerySelectPanel {...props} />);
|
||||||
|
expect(wrapper.exists("#availableCheckbox")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should checked availableCheckbox by default", () => {
|
||||||
|
const wrapper = mount(<TableQuerySelectPanel {...props} />);
|
||||||
|
expect(wrapper.find("#availableCheckbox").first().props()).toEqual({
|
||||||
|
id: "availableCheckbox",
|
||||||
|
label: "Available Columns",
|
||||||
|
checked: true,
|
||||||
|
onChange: expect.any(Function),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
155
src/Explorer/Panes/Tables/TableQuerySelectPanel/index.tsx
Normal file
155
src/Explorer/Panes/Tables/TableQuerySelectPanel/index.tsx
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
import { Checkbox, Text } from "office-ui-fabric-react";
|
||||||
|
import React, { FunctionComponent, useEffect, useState } from "react";
|
||||||
|
import { userContext } from "../../../../UserContext";
|
||||||
|
import Explorer from "../../../Explorer";
|
||||||
|
import * as Constants from "../../../Tables/Constants";
|
||||||
|
import QueryViewModel from "../../../Tables/QueryBuilder/QueryViewModel";
|
||||||
|
import { GenericRightPaneComponent, GenericRightPaneProps } from "../../GenericRightPaneComponent";
|
||||||
|
|
||||||
|
interface TableQuerySelectPanelProps {
|
||||||
|
explorer: Explorer;
|
||||||
|
closePanel: () => void;
|
||||||
|
queryViewModel: QueryViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ISelectColumn {
|
||||||
|
columnName: string;
|
||||||
|
selected: boolean;
|
||||||
|
editable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TableQuerySelectPanel: FunctionComponent<TableQuerySelectPanelProps> = ({
|
||||||
|
explorer,
|
||||||
|
closePanel,
|
||||||
|
queryViewModel,
|
||||||
|
}: TableQuerySelectPanelProps): JSX.Element => {
|
||||||
|
const [columnOptions, setColumnOptions] = useState<ISelectColumn[]>([
|
||||||
|
{ columnName: "", selected: true, editable: false },
|
||||||
|
]);
|
||||||
|
const [isAvailableColumnChecked, setIsAvailableColumnChecked] = useState<boolean>(true);
|
||||||
|
|
||||||
|
const genericPaneProps: GenericRightPaneProps = {
|
||||||
|
container: explorer,
|
||||||
|
formError: "",
|
||||||
|
formErrorDetail: "",
|
||||||
|
id: "querySelectPane",
|
||||||
|
isExecuting: false,
|
||||||
|
title: "Select Column",
|
||||||
|
submitButtonText: "OK",
|
||||||
|
onClose: () => closePanel(),
|
||||||
|
onSubmit: () => submit(),
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = (): void => {
|
||||||
|
queryViewModel.selectText(getParameters());
|
||||||
|
queryViewModel.getSelectMessage();
|
||||||
|
closePanel();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClick = (isChecked: boolean, selectedColumn: string): void => {
|
||||||
|
const columns = columnOptions.map((column) => {
|
||||||
|
if (column.columnName === selectedColumn) {
|
||||||
|
column.selected = isChecked;
|
||||||
|
return { ...column };
|
||||||
|
}
|
||||||
|
return { ...column };
|
||||||
|
});
|
||||||
|
canSelectAll();
|
||||||
|
setColumnOptions(columns);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
queryViewModel && setTableColumns(queryViewModel.columnOptions());
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const setTableColumns = (columnNames: string[]): void => {
|
||||||
|
const columns: ISelectColumn[] =
|
||||||
|
columnNames &&
|
||||||
|
columnNames.length &&
|
||||||
|
columnNames.map((value: string) => {
|
||||||
|
const columnOption: ISelectColumn = {
|
||||||
|
columnName: value,
|
||||||
|
selected: true,
|
||||||
|
editable: isEntityEditable(value),
|
||||||
|
};
|
||||||
|
return columnOption;
|
||||||
|
});
|
||||||
|
setColumnOptions(columns);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isEntityEditable = (name: string): boolean => {
|
||||||
|
if (userContext.apiType === "Cassandra") {
|
||||||
|
const cassandraKeys = queryViewModel.queryTablesTab.collection.cassandraKeys.partitionKeys
|
||||||
|
.concat(queryViewModel.queryTablesTab.collection.cassandraKeys.clusteringKeys)
|
||||||
|
.map((key) => key.property);
|
||||||
|
return !cassandraKeys.includes(name);
|
||||||
|
}
|
||||||
|
return !(
|
||||||
|
name === Constants.EntityKeyNames.PartitionKey ||
|
||||||
|
name === Constants.EntityKeyNames.RowKey ||
|
||||||
|
name === Constants.EntityKeyNames.Timestamp
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const availableColumnsCheckboxClick = (event: React.FormEvent<HTMLElement>, isChecked: boolean): void => {
|
||||||
|
setIsAvailableColumnChecked(isChecked);
|
||||||
|
selectClearAll(isChecked);
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectClearAll = (isChecked: boolean): void => {
|
||||||
|
const columns: ISelectColumn[] = columnOptions.map((column: ISelectColumn) => {
|
||||||
|
if (isEntityEditable(column.columnName)) {
|
||||||
|
column.selected = isChecked;
|
||||||
|
return { ...column };
|
||||||
|
}
|
||||||
|
return { ...column };
|
||||||
|
});
|
||||||
|
setColumnOptions(columns);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getParameters = (): string[] => {
|
||||||
|
const selectedColumns = columnOptions.filter((value: ISelectColumn) => value.selected === true);
|
||||||
|
const columns: string[] = selectedColumns.map((value: ISelectColumn) => {
|
||||||
|
const name: string = value.columnName;
|
||||||
|
return name;
|
||||||
|
});
|
||||||
|
|
||||||
|
return columns;
|
||||||
|
};
|
||||||
|
|
||||||
|
const canSelectAll = (): void => {
|
||||||
|
const canSelectAllColumn: boolean = columnOptions.some((value: ISelectColumn) => {
|
||||||
|
return !value.selected;
|
||||||
|
});
|
||||||
|
setIsAvailableColumnChecked(!canSelectAllColumn);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GenericRightPaneComponent {...genericPaneProps}>
|
||||||
|
<div className="panelFormWrapper">
|
||||||
|
<div className="panelMainContent">
|
||||||
|
<Text>Select the columns that you want to query.</Text>
|
||||||
|
<div className="column-select-view">
|
||||||
|
<Checkbox
|
||||||
|
id="availableCheckbox"
|
||||||
|
label="Available Columns"
|
||||||
|
checked={isAvailableColumnChecked}
|
||||||
|
onChange={availableColumnsCheckboxClick}
|
||||||
|
/>
|
||||||
|
{columnOptions.map((column) => {
|
||||||
|
return (
|
||||||
|
<Checkbox
|
||||||
|
label={column.columnName}
|
||||||
|
onChange={(_event, isChecked: boolean) => handleClick(isChecked, column.columnName)}
|
||||||
|
key={column.columnName}
|
||||||
|
checked={column.selected}
|
||||||
|
disabled={!column.editable}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</GenericRightPaneComponent>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -238,27 +238,6 @@ exports[`Upload Items Pane should render Default properly 1`] = `
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
NewVertexPane {
|
NewVertexPane {
|
||||||
"buildString": [Function],
|
"buildString": [Function],
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
@@ -716,27 +695,6 @@ exports[`Upload Items Pane should render Default properly 1`] = `
|
|||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"querySelectPane": QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"refreshDatabaseAccount": [Function],
|
"refreshDatabaseAccount": [Function],
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
verticalAlign="start"
|
verticalAlign="start"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-Stack panelInfoErrorContainer css-140"
|
className="ms-Stack panelInfoErrorContainer css-108"
|
||||||
>
|
>
|
||||||
<StyledIconBase
|
<StyledIconBase
|
||||||
className="panelWarningIcon"
|
className="panelWarningIcon"
|
||||||
@@ -317,7 +317,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
aria-hidden={true}
|
aria-hidden={true}
|
||||||
className="panelWarningIcon root-142"
|
className="panelWarningIcon root-110"
|
||||||
data-icon-name="WarningSolid"
|
data-icon-name="WarningSolid"
|
||||||
>
|
>
|
||||||
|
|
||||||
@@ -333,7 +333,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
variant="small"
|
variant="small"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="panelWarningErrorMessage css-143"
|
className="panelWarningErrorMessage css-111"
|
||||||
>
|
>
|
||||||
Warning! The action you are about to take cannot be undone. Continuing will permanently delete this resource and all of its children resources.
|
Warning! The action you are about to take cannot be undone. Continuing will permanently delete this resource and all of its children resources.
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
variant="small"
|
variant="small"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="css-143"
|
className="css-111"
|
||||||
>
|
>
|
||||||
Confirm by typing the collection id
|
Confirm by typing the collection id
|
||||||
</span>
|
</span>
|
||||||
@@ -659,18 +659,18 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
validateOnLoad={true}
|
validateOnLoad={true}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-TextField root-145"
|
className="ms-TextField root-113"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-TextField-wrapper"
|
className="ms-TextField-wrapper"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-TextField-fieldGroup fieldGroup-146"
|
className="ms-TextField-fieldGroup fieldGroup-114"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
aria-invalid={false}
|
aria-invalid={false}
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
className="ms-TextField-field field-147"
|
className="ms-TextField-field field-115"
|
||||||
id="confirmCollectionId"
|
id="confirmCollectionId"
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
@@ -693,7 +693,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
variant="small"
|
variant="small"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="css-156"
|
className="css-124"
|
||||||
>
|
>
|
||||||
Help us improve Azure Cosmos DB!
|
Help us improve Azure Cosmos DB!
|
||||||
</span>
|
</span>
|
||||||
@@ -703,7 +703,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
variant="small"
|
variant="small"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="css-156"
|
className="css-124"
|
||||||
>
|
>
|
||||||
What is the reason why you are deleting this container?
|
What is the reason why you are deleting this container?
|
||||||
</span>
|
</span>
|
||||||
@@ -1006,17 +1006,17 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
validateOnLoad={true}
|
validateOnLoad={true}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-TextField ms-TextField--multiline root-145"
|
className="ms-TextField ms-TextField--multiline root-113"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-TextField-wrapper"
|
className="ms-TextField-wrapper"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="ms-TextField-fieldGroup fieldGroup-157"
|
className="ms-TextField-fieldGroup fieldGroup-125"
|
||||||
>
|
>
|
||||||
<textarea
|
<textarea
|
||||||
aria-invalid={false}
|
aria-invalid={false}
|
||||||
className="ms-TextField-field field-158"
|
className="ms-TextField-field field-126"
|
||||||
id="deleteCollectionFeedbackInput"
|
id="deleteCollectionFeedbackInput"
|
||||||
onBlur={[Function]}
|
onBlur={[Function]}
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
@@ -2708,7 +2708,7 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
variantClassName="ms-Button--primary"
|
variantClassName="ms-Button--primary"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
className="ms-Button ms-Button--primary root-160"
|
className="ms-Button ms-Button--primary root-128"
|
||||||
data-is-focusable={true}
|
data-is-focusable={true}
|
||||||
id="sidePanelOkButton"
|
id="sidePanelOkButton"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
@@ -2720,14 +2720,14 @@ exports[`Delete Collection Confirmation Pane submit() should call delete collect
|
|||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="ms-Button-flexContainer flexContainer-161"
|
className="ms-Button-flexContainer flexContainer-129"
|
||||||
data-automationid="splitbuttonprimary"
|
data-automationid="splitbuttonprimary"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="ms-Button-textContainer textContainer-162"
|
className="ms-Button-textContainer textContainer-130"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className="ms-Button-label label-164"
|
className="ms-Button-label label-132"
|
||||||
id="id__6"
|
id="id__6"
|
||||||
key="id__6"
|
key="id__6"
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -239,27 +239,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
|||||||
"title": [Function],
|
"title": [Function],
|
||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
NewVertexPane {
|
NewVertexPane {
|
||||||
"buildString": [Function],
|
"buildString": [Function],
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
@@ -720,27 +699,6 @@ exports[`Delete Database Confirmation Pane submit() Should call delete database
|
|||||||
"queriesClient": QueriesClient {
|
"queriesClient": QueriesClient {
|
||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"querySelectPane": QuerySelectPane {
|
|
||||||
"allSelected": [Function],
|
|
||||||
"anyColumnSelected": [Function],
|
|
||||||
"availableColumnsTableQueryLabel": "Available Columns",
|
|
||||||
"canSelectAll": [Function],
|
|
||||||
"columnOptions": [Function],
|
|
||||||
"container": [Circular],
|
|
||||||
"firstFieldHasFocus": [Function],
|
|
||||||
"formErrors": [Function],
|
|
||||||
"formErrorsDetails": [Function],
|
|
||||||
"handleClick": [Function],
|
|
||||||
"id": "queryselectpane",
|
|
||||||
"instructionLabel": "Select the columns that you want to query.",
|
|
||||||
"isExecuting": [Function],
|
|
||||||
"isTemplateReady": [Function],
|
|
||||||
"noColumnSelectedWarning": "At least one column should be selected.",
|
|
||||||
"selectedColumnOption": null,
|
|
||||||
"title": [Function],
|
|
||||||
"titleLabel": "Select Columns",
|
|
||||||
"visible": [Function],
|
|
||||||
},
|
|
||||||
"refreshAllDatabases": [Function],
|
"refreshAllDatabases": [Function],
|
||||||
"refreshDatabaseAccount": [Function],
|
"refreshDatabaseAccount": [Function],
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
import * as _ from "underscore";
|
import * as _ from "underscore";
|
||||||
|
import { KeyCodes } from "../../../Common/Constants";
|
||||||
|
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
||||||
|
import { getQuotedCqlIdentifier } from "../CqlUtilities";
|
||||||
|
import * as DataTableUtilities from "../DataTable/DataTableUtilities";
|
||||||
|
import TableEntityListViewModel from "../DataTable/TableEntityListViewModel";
|
||||||
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
import QueryBuilderViewModel from "./QueryBuilderViewModel";
|
||||||
import QueryClauseViewModel from "./QueryClauseViewModel";
|
import QueryClauseViewModel from "./QueryClauseViewModel";
|
||||||
import TableEntityListViewModel from "../DataTable/TableEntityListViewModel";
|
|
||||||
import QueryTablesTab from "../../Tabs/QueryTablesTab";
|
|
||||||
import * as DataTableUtilities from "../DataTable/DataTableUtilities";
|
|
||||||
import { KeyCodes } from "../../../Common/Constants";
|
|
||||||
import { getQuotedCqlIdentifier } from "../CqlUtilities";
|
|
||||||
|
|
||||||
export default class QueryViewModel {
|
export default class QueryViewModel {
|
||||||
public topValueLimitMessage: string = "Please input a number between 0 and 1000.";
|
public topValueLimitMessage: string = "Please input a number between 0 and 1000.";
|
||||||
@@ -198,8 +197,7 @@ export default class QueryViewModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public selectQueryOptions(): Promise<any> {
|
public selectQueryOptions(): Promise<any> {
|
||||||
this.queryTablesTab.container.querySelectPane.queryViewModel = this;
|
this.queryTablesTab.container.openTableSelectQueryPanel(this);
|
||||||
this.queryTablesTab.container.querySelectPane.open();
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -236,7 +236,6 @@ const App: React.FunctionComponent = () => {
|
|||||||
<div data-bind='component: { name: "graph-styling-pane", params: { data: graphStylingPane} }' />
|
<div data-bind='component: { name: "graph-styling-pane", params: { data: graphStylingPane} }' />
|
||||||
<div data-bind='component: { name: "table-add-entity-pane", params: { data: addTableEntityPane} }' />
|
<div data-bind='component: { name: "table-add-entity-pane", params: { data: addTableEntityPane} }' />
|
||||||
<div data-bind='component: { name: "table-edit-entity-pane", params: { data: editTableEntityPane} }' />
|
<div data-bind='component: { name: "table-edit-entity-pane", params: { data: editTableEntityPane} }' />
|
||||||
<div data-bind='component: { name: "table-query-select-pane", params: { data: querySelectPane} }' />
|
|
||||||
<div data-bind='component: { name: "cassandra-add-collection-pane", params: { data: cassandraAddCollectionPane} }' />
|
<div data-bind='component: { name: "cassandra-add-collection-pane", params: { data: cassandraAddCollectionPane} }' />
|
||||||
<div data-bind='component: { name: "string-input-pane", params: { data: stringInputPane} }' />
|
<div data-bind='component: { name: "string-input-pane", params: { data: stringInputPane} }' />
|
||||||
<div data-bind='component: { name: "setup-notebooks-pane", params: { data: setupNotebooksPane} }' />
|
<div data-bind='component: { name: "setup-notebooks-pane", params: { data: setupNotebooksPane} }' />
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
import { Callout, DefaultButton, DirectionalHint, Stack, TextField } from "office-ui-fabric-react";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
export interface DropdownItem {
|
|
||||||
key: string;
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SearchableDropdownProps {
|
|
||||||
items: DropdownItem[];
|
|
||||||
onItemSelected: (selectedItem: DropdownItem) => void;
|
|
||||||
defaultSelectedItem?: DropdownItem;
|
|
||||||
placeholder?: string;
|
|
||||||
title?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SearchableDropdownState {
|
|
||||||
isDropdownExpanded: boolean;
|
|
||||||
selectedItem: DropdownItem;
|
|
||||||
filteredItems: DropdownItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SearchableDropdown extends React.Component<SearchableDropdownProps, SearchableDropdownState> {
|
|
||||||
constructor(props: SearchableDropdownProps) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
isDropdownExpanded: false,
|
|
||||||
selectedItem: props.defaultSelectedItem,
|
|
||||||
filteredItems: props.items,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): JSX.Element {
|
|
||||||
return this.state.isDropdownExpanded ? (
|
|
||||||
<Stack>
|
|
||||||
<TextField
|
|
||||||
className="dropdownTextField"
|
|
||||||
title={this.props.title}
|
|
||||||
onChange={(event, newInput?: string) => this.onSearchInputChange(newInput)}
|
|
||||||
placeholder={this.props.placeholder}
|
|
||||||
autoFocus
|
|
||||||
/>
|
|
||||||
<Callout
|
|
||||||
isBeakVisible={false}
|
|
||||||
target=".dropdownTextField"
|
|
||||||
directionalHint={DirectionalHint.rightTopEdge}
|
|
||||||
onDismiss={() => this.setState({ isDropdownExpanded: false })}
|
|
||||||
gapSpace={0}
|
|
||||||
>
|
|
||||||
<Stack>
|
|
||||||
{this.state.filteredItems?.map((item) => (
|
|
||||||
<DefaultButton
|
|
||||||
key={item.key}
|
|
||||||
text={item.text}
|
|
||||||
style={{ border: "none", textAlign: "left" }}
|
|
||||||
styles={{ label: { fontWeight: "normal" } }}
|
|
||||||
onClick={() => this.onItemSelected(item)}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Stack>
|
|
||||||
</Callout>
|
|
||||||
</Stack>
|
|
||||||
) : (
|
|
||||||
<TextField
|
|
||||||
className="dropdownTextField"
|
|
||||||
title={this.props.title}
|
|
||||||
onClick={() => this.setState({ isDropdownExpanded: true, filteredItems: this.props.items })}
|
|
||||||
value={this.state.selectedItem?.text || ""}
|
|
||||||
placeholder={this.props.placeholder}
|
|
||||||
readOnly
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private onSearchInputChange(newInput: string): void {
|
|
||||||
const filteredItems = this.props.items.filter((item: DropdownItem) =>
|
|
||||||
item.text.toLocaleLowerCase().includes(newInput.toLocaleLowerCase())
|
|
||||||
);
|
|
||||||
this.setState({ filteredItems });
|
|
||||||
}
|
|
||||||
|
|
||||||
private onItemSelected(item: DropdownItem): void {
|
|
||||||
this.setState({ selectedItem: item, isDropdownExpanded: false });
|
|
||||||
this.props.onItemSelected(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from "react";
|
import { Dropdown } from "office-ui-fabric-react/lib/Dropdown";
|
||||||
|
import * as React from "react";
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
import { DatabaseAccount } from "../../../Contracts/DataModels";
|
import { DatabaseAccount } from "../../../Contracts/DataModels";
|
||||||
import { DropdownItem, SearchableDropdown } from "./SearchableDropdown";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
accounts: DatabaseAccount[];
|
accounts: DatabaseAccount[];
|
||||||
@@ -9,32 +10,30 @@ interface Props {
|
|||||||
dismissMenu: () => void;
|
dismissMenu: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SwitchAccount: React.FunctionComponent<Props> = ({
|
export const SwitchAccount: FunctionComponent<Props> = ({
|
||||||
accounts,
|
accounts,
|
||||||
setSelectedAccountName,
|
setSelectedAccountName,
|
||||||
selectedAccount,
|
selectedAccount,
|
||||||
dismissMenu,
|
dismissMenu,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const accountItems = accounts?.map((account) => ({
|
|
||||||
key: account.name,
|
|
||||||
text: account.name,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const defaultAccount = selectedAccount && {
|
|
||||||
key: selectedAccount.name,
|
|
||||||
text: selectedAccount.name,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SearchableDropdown
|
<Dropdown
|
||||||
items={accountItems}
|
label="Cosmos DB Account Name"
|
||||||
title="Cosmos DB Account Name"
|
className="accountSwitchAccountDropdown"
|
||||||
defaultSelectedItem={defaultAccount}
|
options={accounts?.map((account) => ({
|
||||||
placeholder={accounts?.length === 0 ? "No Accounts Found" : "Select an Account"}
|
key: account.name,
|
||||||
onItemSelected={(accountItem: DropdownItem) => {
|
text: account.name,
|
||||||
setSelectedAccountName(accountItem.key);
|
data: account,
|
||||||
|
}))}
|
||||||
|
onChange={(_, option) => {
|
||||||
|
setSelectedAccountName(String(option.key));
|
||||||
dismissMenu();
|
dismissMenu();
|
||||||
}}
|
}}
|
||||||
|
defaultSelectedKey={selectedAccount?.name}
|
||||||
|
placeholder={accounts && accounts.length === 0 ? "No Accounts Found" : "Select an Account"}
|
||||||
|
styles={{
|
||||||
|
callout: "accountSwitchAccountDropdownMenu",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from "react";
|
import { Dropdown } from "office-ui-fabric-react/lib/Dropdown";
|
||||||
|
import * as React from "react";
|
||||||
|
import { FunctionComponent } from "react";
|
||||||
import { Subscription } from "../../../Contracts/DataModels";
|
import { Subscription } from "../../../Contracts/DataModels";
|
||||||
import { DropdownItem, SearchableDropdown } from "./SearchableDropdown";
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
subscriptions: Subscription[];
|
subscriptions: Subscription[];
|
||||||
@@ -8,28 +9,30 @@ interface Props {
|
|||||||
setSelectedSubscriptionId: (id: string) => void;
|
setSelectedSubscriptionId: (id: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SwitchSubscription: React.FunctionComponent<Props> = ({
|
export const SwitchSubscription: FunctionComponent<Props> = ({
|
||||||
subscriptions,
|
subscriptions,
|
||||||
setSelectedSubscriptionId,
|
setSelectedSubscriptionId,
|
||||||
selectedSubscription,
|
selectedSubscription,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const subscriptionItems = subscriptions?.map((sub) => ({
|
|
||||||
key: sub.subscriptionId,
|
|
||||||
text: sub.displayName,
|
|
||||||
}));
|
|
||||||
|
|
||||||
const defaultSubscription = selectedSubscription && {
|
|
||||||
key: selectedSubscription.subscriptionId,
|
|
||||||
text: selectedSubscription.displayName,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SearchableDropdown
|
<Dropdown
|
||||||
items={subscriptionItems}
|
label="Subscription"
|
||||||
title="Subscription"
|
className="accountSwitchSubscriptionDropdown"
|
||||||
defaultSelectedItem={defaultSubscription}
|
options={subscriptions?.map((sub) => {
|
||||||
placeholder={subscriptions?.length === 0 ? "No Subscriptions Found" : "Select a Subscription"}
|
return {
|
||||||
onItemSelected={(subscriptionItem: DropdownItem) => setSelectedSubscriptionId(subscriptionItem.key)}
|
key: sub.subscriptionId,
|
||||||
|
text: sub.displayName,
|
||||||
|
data: sub,
|
||||||
|
};
|
||||||
|
})}
|
||||||
|
onChange={(_, option) => {
|
||||||
|
setSelectedSubscriptionId(String(option.key));
|
||||||
|
}}
|
||||||
|
defaultSelectedKey={selectedSubscription?.subscriptionId}
|
||||||
|
placeholder={subscriptions && subscriptions.length === 0 ? "No Subscriptions Found" : "Select a Subscription"}
|
||||||
|
styles={{
|
||||||
|
callout: "accountSwitchSubscriptionDropdownMenu",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,12 +17,14 @@ export type Features = {
|
|||||||
readonly notebookBasePath?: string;
|
readonly notebookBasePath?: string;
|
||||||
readonly notebookServerToken?: string;
|
readonly notebookServerToken?: string;
|
||||||
readonly notebookServerUrl?: string;
|
readonly notebookServerUrl?: string;
|
||||||
|
readonly sandboxNotebookOutputs: boolean;
|
||||||
readonly selfServeType?: string;
|
readonly selfServeType?: string;
|
||||||
|
readonly pr?: string;
|
||||||
readonly showMinRUSurvey: boolean;
|
readonly showMinRUSurvey: boolean;
|
||||||
readonly ttl90Days: boolean;
|
readonly ttl90Days: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function extractFeatures(given = new URLSearchParams()): Features {
|
export function extractFeatures(given = new URLSearchParams(window.location.search)): Features {
|
||||||
const downcased = new URLSearchParams();
|
const downcased = new URLSearchParams();
|
||||||
const set = (value: string, key: string) => downcased.set(key.toLowerCase(), value);
|
const set = (value: string, key: string) => downcased.set(key.toLowerCase(), value);
|
||||||
const get = (key: string) => downcased.get("feature." + key) ?? undefined;
|
const get = (key: string) => downcased.get("feature." + key) ?? undefined;
|
||||||
@@ -54,7 +56,9 @@ export function extractFeatures(given = new URLSearchParams()): Features {
|
|||||||
notebookBasePath: get("notebookbasepath"),
|
notebookBasePath: get("notebookbasepath"),
|
||||||
notebookServerToken: get("notebookservertoken"),
|
notebookServerToken: get("notebookservertoken"),
|
||||||
notebookServerUrl: get("notebookserverurl"),
|
notebookServerUrl: get("notebookserverurl"),
|
||||||
|
sandboxNotebookOutputs: "true" === get("sandboxnotebookoutputs"),
|
||||||
selfServeType: get("selfservetype"),
|
selfServeType: get("selfservetype"),
|
||||||
|
pr: get("pr"),
|
||||||
showMinRUSurvey: "true" === get("showminrusurvey"),
|
showMinRUSurvey: "true" === get("showminrusurvey"),
|
||||||
ttl90Days: "true" === get("ttl90days"),
|
ttl90Days: "true" === get("ttl90days"),
|
||||||
};
|
};
|
||||||
|
|||||||
23
src/Utils/StyleUtils.ts
Normal file
23
src/Utils/StyleUtils.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Adapted from https://gist.github.com/davidgilbertson/ed3c8bb8569bc64b094b87aa88bed5fa
|
||||||
|
export function copyStyles(sourceDoc: Document, targetDoc: Document): void {
|
||||||
|
Array.from(sourceDoc.styleSheets).forEach((styleSheet) => {
|
||||||
|
if (styleSheet.href) {
|
||||||
|
// for <link> elements loading CSS from a URL
|
||||||
|
const newLinkEl = sourceDoc.createElement("link");
|
||||||
|
|
||||||
|
newLinkEl.rel = "stylesheet";
|
||||||
|
newLinkEl.href = styleSheet.href;
|
||||||
|
targetDoc.head.appendChild(newLinkEl);
|
||||||
|
} else if (styleSheet.cssRules && styleSheet.cssRules.length > 0) {
|
||||||
|
// for <style> elements
|
||||||
|
const newStyleEl = sourceDoc.createElement("style");
|
||||||
|
|
||||||
|
Array.from(styleSheet.cssRules).forEach((cssRule) => {
|
||||||
|
// write the text of each rule into the body of the style element
|
||||||
|
newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText));
|
||||||
|
});
|
||||||
|
|
||||||
|
targetDoc.head.appendChild(newStyleEl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -201,11 +201,12 @@ async function configurePortal(explorerParams: ExplorerParams): Promise<Explorer
|
|||||||
if (process.env.NODE_ENV === "development" && !window.location.search.includes("disablePortalInitCache")) {
|
if (process.env.NODE_ENV === "development" && !window.location.search.includes("disablePortalInitCache")) {
|
||||||
const initMessage = sessionStorage.getItem("portalDataExplorerInitMessage");
|
const initMessage = sessionStorage.getItem("portalDataExplorerInitMessage");
|
||||||
if (initMessage) {
|
if (initMessage) {
|
||||||
const message = JSON.parse(initMessage);
|
const message = JSON.parse(initMessage) as DataExplorerInputsFrame;
|
||||||
console.warn(
|
console.warn(
|
||||||
"Loaded cached portal iframe message from session storage. Do a full page refresh to get a new message"
|
"Loaded cached portal iframe message from session storage. Do a full page refresh to get a new message"
|
||||||
);
|
);
|
||||||
console.dir(message);
|
console.dir(message);
|
||||||
|
updateContextsFromPortalMessage(message);
|
||||||
const explorer = new Explorer(explorerParams);
|
const explorer = new Explorer(explorerParams);
|
||||||
explorer.configure(message);
|
explorer.configure(message);
|
||||||
resolve(explorer);
|
resolve(explorer);
|
||||||
@@ -237,29 +238,7 @@ async function configurePortal(explorerParams: ExplorerParams): Promise<Explorer
|
|||||||
inputs.extensionEndpoint = configContext.PROXY_PATH;
|
inputs.extensionEndpoint = configContext.PROXY_PATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
const authorizationToken = inputs.authorizationToken || "";
|
updateContextsFromPortalMessage(inputs);
|
||||||
const masterKey = inputs.masterKey || "";
|
|
||||||
const databaseAccount = inputs.databaseAccount;
|
|
||||||
|
|
||||||
updateConfigContext({
|
|
||||||
BACKEND_ENDPOINT: inputs.extensionEndpoint || configContext.BACKEND_ENDPOINT,
|
|
||||||
ARM_ENDPOINT: normalizeArmEndpoint(inputs.csmEndpoint || configContext.ARM_ENDPOINT),
|
|
||||||
});
|
|
||||||
|
|
||||||
updateUserContext({
|
|
||||||
authorizationToken,
|
|
||||||
masterKey,
|
|
||||||
databaseAccount,
|
|
||||||
resourceGroup: inputs.resourceGroup,
|
|
||||||
subscriptionId: inputs.subscriptionId,
|
|
||||||
subscriptionType: inputs.subscriptionType,
|
|
||||||
quotaId: inputs.quotaId,
|
|
||||||
portalEnv: inputs.serverId as PortalEnv,
|
|
||||||
hasWriteAccess: inputs.hasWriteAccess ?? true,
|
|
||||||
addCollectionFlight:
|
|
||||||
inputs.addCollectionDefaultFlight || CollectionCreation.DefaultAddCollectionDefaultFlight,
|
|
||||||
});
|
|
||||||
|
|
||||||
const explorer = new Explorer(explorerParams);
|
const explorer = new Explorer(explorerParams);
|
||||||
explorer.configure(inputs);
|
explorer.configure(inputs);
|
||||||
resolve(explorer);
|
resolve(explorer);
|
||||||
@@ -299,6 +278,38 @@ function shouldProcessMessage(event: MessageEvent): boolean {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateContextsFromPortalMessage(inputs: DataExplorerInputsFrame) {
|
||||||
|
if (
|
||||||
|
configContext.BACKEND_ENDPOINT &&
|
||||||
|
configContext.platform === Platform.Portal &&
|
||||||
|
process.env.NODE_ENV === "development"
|
||||||
|
) {
|
||||||
|
inputs.extensionEndpoint = configContext.PROXY_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorizationToken = inputs.authorizationToken || "";
|
||||||
|
const masterKey = inputs.masterKey || "";
|
||||||
|
const databaseAccount = inputs.databaseAccount;
|
||||||
|
|
||||||
|
updateConfigContext({
|
||||||
|
BACKEND_ENDPOINT: inputs.extensionEndpoint || configContext.BACKEND_ENDPOINT,
|
||||||
|
ARM_ENDPOINT: normalizeArmEndpoint(inputs.csmEndpoint || configContext.ARM_ENDPOINT),
|
||||||
|
});
|
||||||
|
|
||||||
|
updateUserContext({
|
||||||
|
authorizationToken,
|
||||||
|
masterKey,
|
||||||
|
databaseAccount,
|
||||||
|
resourceGroup: inputs.resourceGroup,
|
||||||
|
subscriptionId: inputs.subscriptionId,
|
||||||
|
subscriptionType: inputs.subscriptionType,
|
||||||
|
quotaId: inputs.quotaId,
|
||||||
|
portalEnv: inputs.serverId as PortalEnv,
|
||||||
|
hasWriteAccess: inputs.hasWriteAccess ?? true,
|
||||||
|
addCollectionFlight: inputs.addCollectionDefaultFlight || CollectionCreation.DefaultAddCollectionDefaultFlight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
interface PortalMessage {
|
interface PortalMessage {
|
||||||
openAction?: DataExplorerAction;
|
openAction?: DataExplorerAction;
|
||||||
actionType?: ActionType;
|
actionType?: ActionType;
|
||||||
|
|||||||
1
strict-migration-tools/.gitignore
vendored
1
strict-migration-tools/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
node_modules
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
Borrowed from https://github.com/mjbvz/vscode-strict-null-check-migration-tools/tree/f1da7c12fe6e93618a310cb3662e2ade808be0c4
|
|
||||||
|
|
||||||
Scripts to help [migrate VS Code to use strict null checks](https://github.com/Microsoft/vscode/issues/60565)
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
**index.js**
|
|
||||||
|
|
||||||
The main script prints of list of files that are eligible for strict null checks. This includes all files that only import files thare are already strict null checked.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ node index.js /path/to/vscode
|
|
||||||
```
|
|
||||||
|
|
||||||
**autoAdd.js**
|
|
||||||
|
|
||||||
Very simple script that tries to auto add any eligible file to the `tsconfig.strictNullChecks.json`. This iteratively compiles the `tsconfig` project with just that file added. If there are no errors, it is added to the `tsconfig`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ node autoAdd.js /path/to/vscode
|
|
||||||
```
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
// @ts-check
|
|
||||||
const path = require("path");
|
|
||||||
const fs = require("fs");
|
|
||||||
const child_process = require("child_process");
|
|
||||||
const config = require("./src/config");
|
|
||||||
const { forStrictNullCheckEligibleFiles } = require("./src/getStrictNullCheckEligibleFiles");
|
|
||||||
|
|
||||||
const vscodeRoot = path.join(process.cwd());
|
|
||||||
const srcRoot = path.join(vscodeRoot, "src");
|
|
||||||
|
|
||||||
const buildCompletePattern = /Found (\d+) errors?\. Watching for file changes\./gi;
|
|
||||||
|
|
||||||
forStrictNullCheckEligibleFiles(vscodeRoot, () => {}).then(async files => {
|
|
||||||
const tsconfigPath = path.join(srcRoot, config.targetTsconfig);
|
|
||||||
|
|
||||||
const child = child_process.spawn("tsc", ["-p", tsconfigPath, "--watch"]);
|
|
||||||
for (const file of files) {
|
|
||||||
await tryAutoAddStrictNulls(child, tsconfigPath, file);
|
|
||||||
}
|
|
||||||
child.kill();
|
|
||||||
});
|
|
||||||
|
|
||||||
function tryAutoAddStrictNulls(child, tsconfigPath, file) {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const relativeFilePath = path.relative(srcRoot, file);
|
|
||||||
console.log(`Trying to auto add ./src/${relativeFilePath}`);
|
|
||||||
|
|
||||||
const originalConifg = JSON.parse(fs.readFileSync(tsconfigPath).toString());
|
|
||||||
originalConifg.files = Array.from(new Set(originalConifg.files.sort()));
|
|
||||||
|
|
||||||
// Config on accept
|
|
||||||
const newConfig = Object.assign({}, originalConifg);
|
|
||||||
newConfig.files = Array.from(new Set(originalConifg.files.concat("./src/" + relativeFilePath).sort()));
|
|
||||||
|
|
||||||
fs.writeFileSync(tsconfigPath, JSON.stringify(newConfig, null, "\t"));
|
|
||||||
|
|
||||||
const listener = data => {
|
|
||||||
const textOut = data.toString();
|
|
||||||
const match = buildCompletePattern.exec(textOut);
|
|
||||||
if (match) {
|
|
||||||
const errorCount = +match[1];
|
|
||||||
if (errorCount === 0) {
|
|
||||||
console.log(`👍`);
|
|
||||||
fs.writeFileSync(tsconfigPath, JSON.stringify(newConfig, null, "\t"));
|
|
||||||
} else {
|
|
||||||
console.log(`💥 - ${errorCount}`);
|
|
||||||
fs.writeFileSync(tsconfigPath, JSON.stringify(originalConifg, null, "\t"));
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
child.stdout.removeListener("data", listener);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
child.stdout.on("data", listener);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
// @ts-check
|
|
||||||
const path = require("path");
|
|
||||||
const glob = require("glob");
|
|
||||||
const { forStrictNullCheckEligibleFiles, forEachFileInSrc } = require("./src/getStrictNullCheckEligibleFiles");
|
|
||||||
const { getImportsForFile } = require("./src/tsHelper");
|
|
||||||
|
|
||||||
const projectRoot = path.join(process.cwd());
|
|
||||||
const srcRoot = path.join(projectRoot, "src");
|
|
||||||
|
|
||||||
let sort = true;
|
|
||||||
let filter;
|
|
||||||
let printDependedOnCount = true;
|
|
||||||
let includeTests = false;
|
|
||||||
|
|
||||||
// if (false) {
|
|
||||||
// // Generate test files listing
|
|
||||||
// sort = false;
|
|
||||||
// filter = x => x.endsWith(".test.ts");
|
|
||||||
// printDependedOnCount = false;
|
|
||||||
// includeTests = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
forStrictNullCheckEligibleFiles(projectRoot, () => {}, { includeTests }).then(async eligibleFiles => {
|
|
||||||
console.log(eligibleFiles);
|
|
||||||
// const eligibleSet = new Set(eligibleFiles);
|
|
||||||
// const dependedOnCount = new Map(eligibleFiles.map(file => [file, 0]));
|
|
||||||
// for (const file of await forEachFileInSrc(srcRoot)) {
|
|
||||||
// if (eligibleSet.has(file)) {
|
|
||||||
// // Already added
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
// for (const imp of getImportsForFile(file, srcRoot)) {
|
|
||||||
// if (dependedOnCount.has(imp)) {
|
|
||||||
// dependedOnCount.set(imp, dependedOnCount.get(imp) + 1);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// let out = Array.from(dependedOnCount.entries());
|
|
||||||
// if (filter) {
|
|
||||||
// out = out.filter(x => filter(x[0]));
|
|
||||||
// }
|
|
||||||
// if (sort) {
|
|
||||||
// out = out.sort((a, b) => b[1] - a[1]);
|
|
||||||
// }
|
|
||||||
// for (const pair of out) {
|
|
||||||
// console.log(toFormattedFilePath(pair[0]) + (printDependedOnCount ? ` — Depended on by **${pair[1]}** files` : ""));
|
|
||||||
// }
|
|
||||||
});
|
|
||||||
|
|
||||||
// function toFormattedFilePath(file) {
|
|
||||||
// // return `"./${path.relative(srcRoot, file)}",`;
|
|
||||||
// return `- [ ] \`"./${path.relative(srcRoot, file)}"\``;
|
|
||||||
// }
|
|
||||||
90
strict-migration-tools/package-lock.json
generated
90
strict-migration-tools/package-lock.json
generated
@@ -1,90 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "vscode-strict-null-tools",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"lockfileVersion": 1,
|
|
||||||
"requires": true,
|
|
||||||
"dependencies": {
|
|
||||||
"balanced-match": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
|
||||||
},
|
|
||||||
"brace-expansion": {
|
|
||||||
"version": "1.1.11",
|
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
|
||||||
"requires": {
|
|
||||||
"balanced-match": "^1.0.0",
|
|
||||||
"concat-map": "0.0.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"concat-map": {
|
|
||||||
"version": "0.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
|
||||||
},
|
|
||||||
"fs.realpath": {
|
|
||||||
"version": "1.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
|
||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
|
||||||
},
|
|
||||||
"glob": {
|
|
||||||
"version": "7.1.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
|
|
||||||
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
|
|
||||||
"requires": {
|
|
||||||
"fs.realpath": "^1.0.0",
|
|
||||||
"inflight": "^1.0.4",
|
|
||||||
"inherits": "2",
|
|
||||||
"minimatch": "^3.0.4",
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"path-is-absolute": "^1.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"inflight": {
|
|
||||||
"version": "1.0.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
|
||||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
|
||||||
"requires": {
|
|
||||||
"once": "^1.3.0",
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"inherits": {
|
|
||||||
"version": "2.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
|
||||||
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
|
|
||||||
},
|
|
||||||
"minimatch": {
|
|
||||||
"version": "3.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
|
||||||
"requires": {
|
|
||||||
"brace-expansion": "^1.1.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"once": {
|
|
||||||
"version": "1.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
|
||||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
|
||||||
"requires": {
|
|
||||||
"wrappy": "1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"path-is-absolute": {
|
|
||||||
"version": "1.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
|
||||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
|
||||||
},
|
|
||||||
"typescript": {
|
|
||||||
"version": "3.1.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.1.2.tgz",
|
|
||||||
"integrity": "sha512-gOoGJWbNnFAfP9FlrSV63LYD5DJqYJHG5ky1kOXSl3pCImn4rqWy/flyq1BRd4iChQsoCqjbQaqtmXO4yCVPCA=="
|
|
||||||
},
|
|
||||||
"wrappy": {
|
|
||||||
"version": "1.0.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "vscode-strict-null-tools",
|
|
||||||
"private": true,
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "",
|
|
||||||
"main": "index.js",
|
|
||||||
"scripts": {
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "Matt Bierner",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"typescript": "3.1.2",
|
|
||||||
"glob": "^7.1.3"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
module.exports.targetTsconfig = "../tsconfig.strict.json";
|
|
||||||
|
|
||||||
module.exports.skippedFiles = new Set([]);
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
// @ts-check
|
|
||||||
const path = require("path");
|
|
||||||
const fs = require("fs");
|
|
||||||
const { getImportsForFile } = require("./tsHelper");
|
|
||||||
const glob = require("glob");
|
|
||||||
const config = require("./config");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} srcRoot
|
|
||||||
* @param {{ includeTests: boolean }} [options]
|
|
||||||
*/
|
|
||||||
const forEachFileInSrc = (srcRoot, options) => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
glob(`${srcRoot}/**/*.ts`, (err, files) => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolve(
|
|
||||||
files.filter(
|
|
||||||
file => !file.endsWith(".d.ts") && (options && options.includeTests ? true : !file.endsWith(".test.ts"))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
module.exports.forEachFileInSrc = forEachFileInSrc;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} vscodeRoot
|
|
||||||
* @param {(file: string) => void} forEach
|
|
||||||
* @param {{ includeTests: boolean }} [options]
|
|
||||||
*/
|
|
||||||
module.exports.forStrictNullCheckEligibleFiles = async (vscodeRoot, forEach, options) => {
|
|
||||||
const srcRoot = path.join(vscodeRoot, "src");
|
|
||||||
|
|
||||||
const tsconfig = JSON.parse(fs.readFileSync(path.join(srcRoot, config.targetTsconfig)).toString());
|
|
||||||
const checkedFiles = await getCheckedFiles(tsconfig, vscodeRoot);
|
|
||||||
|
|
||||||
const imports = new Map();
|
|
||||||
const getMemoizedImportsForFile = (file, srcRoot) => {
|
|
||||||
if (imports.has(file)) {
|
|
||||||
return imports.get(file);
|
|
||||||
}
|
|
||||||
const importList = getImportsForFile(file, srcRoot);
|
|
||||||
imports.set(file, importList);
|
|
||||||
return importList;
|
|
||||||
};
|
|
||||||
|
|
||||||
const files = await forEachFileInSrc(srcRoot, options);
|
|
||||||
return files
|
|
||||||
.filter(file => !checkedFiles.has(file))
|
|
||||||
.filter(file => !config.skippedFiles.has(path.relative(srcRoot, file)))
|
|
||||||
.filter(file => {
|
|
||||||
const allProjImports = getMemoizedImportsForFile(file, srcRoot);
|
|
||||||
|
|
||||||
const nonCheckedImports = allProjImports
|
|
||||||
.filter(x => x !== file)
|
|
||||||
.filter(imp => {
|
|
||||||
if (checkedFiles.has(imp)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Don't treat cycles as blocking
|
|
||||||
const impImports = getMemoizedImportsForFile(imp, srcRoot);
|
|
||||||
return impImports.filter(x => x !== file).filter(x => !checkedFiles.has(x)).length !== 0;
|
|
||||||
});
|
|
||||||
|
|
||||||
const isEdge = nonCheckedImports.length === 0;
|
|
||||||
if (isEdge) {
|
|
||||||
forEach(file);
|
|
||||||
}
|
|
||||||
return isEdge;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
async function getCheckedFiles(tsconfig, srcRoot) {
|
|
||||||
const set = new Set(tsconfig.files.map(include => path.join(srcRoot, include)));
|
|
||||||
const includes = tsconfig.include.map(include => {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
glob(path.join(srcRoot, include), (err, files) => {
|
|
||||||
if (err) {
|
|
||||||
return reject(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const file of files) {
|
|
||||||
set.add(file);
|
|
||||||
}
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
await Promise.all(includes);
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
// @ts-check
|
|
||||||
const path = require("path");
|
|
||||||
const ts = require("typescript");
|
|
||||||
const fs = require("fs");
|
|
||||||
|
|
||||||
module.exports.getImportsForFile = function getImportsForFile(file, srcRoot) {
|
|
||||||
const fileInfo = ts.preProcessFile(fs.readFileSync(file).toString());
|
|
||||||
return fileInfo.importedFiles
|
|
||||||
.map(importedFile => importedFile.fileName)
|
|
||||||
.filter(fileName => !/svg|gif|png|html|less|json|externals|css|ico/.test(fileName)) // remove image imports
|
|
||||||
.filter(x => /\//.test(x)) // remove node modules (the import must contain '/')
|
|
||||||
.filter(x => !/\@/.test(x)) // remove @ scoped modules
|
|
||||||
.filter(
|
|
||||||
x =>
|
|
||||||
!/url-polyfill|office-ui-fabric|rxjs|\@nteract|bootstrap|promise-polyfill|abort-controller|es6-object-assign|es6-symbol|webcrypto-liner|promise.prototype.finally|object.entries/.test(
|
|
||||||
x
|
|
||||||
)
|
|
||||||
) // remove other modules
|
|
||||||
.filter(x => !/worker-loader/.test(x)) // remove other modules
|
|
||||||
.map(fileName => {
|
|
||||||
if (/(^\.\/)|(^\.\.\/)/.test(fileName)) {
|
|
||||||
return path.join(path.dirname(file), fileName);
|
|
||||||
}
|
|
||||||
if (/^vs/.test(fileName)) {
|
|
||||||
return path.join(srcRoot, fileName);
|
|
||||||
}
|
|
||||||
return fileName;
|
|
||||||
})
|
|
||||||
.map(fileName => {
|
|
||||||
if (fs.existsSync(`${fileName}.ts`)) {
|
|
||||||
return `${fileName}.ts`;
|
|
||||||
}
|
|
||||||
if (fs.existsSync(`${fileName}.js`)) {
|
|
||||||
return `${fileName}.js`;
|
|
||||||
}
|
|
||||||
if (fs.existsSync(`${fileName}.d.ts`)) {
|
|
||||||
return `${fileName}.d.ts`;
|
|
||||||
}
|
|
||||||
if (fs.existsSync(`${fileName}.tsx`)) {
|
|
||||||
return `${fileName}.tsx`;
|
|
||||||
}
|
|
||||||
throw new Error(`Unresolved import ${fileName} in ${file}`);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
8
strict-null-checks/README.md
Normal file
8
strict-null-checks/README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<!--
|
||||||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
Licensed under the MIT License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
Scripts to help migrate to use strict null checks.
|
||||||
|
|
||||||
|
Modified from [strict-null-checks](https://github.com/microsoft/accessibility-insights-web/tree/f2ec74cc5f09d41a4b617b0eb941b6da332a4343/tools/strict-null-checks)
|
||||||
100
strict-null-checks/auto-add.js
Normal file
100
strict-null-checks/auto-add.js
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
const child_process = require("child_process");
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const { collapseCompletedDirectories } = require("./collapse-completed-directories");
|
||||||
|
const config = require("./config");
|
||||||
|
const { getUncheckedLeafFiles } = require("./eligible-file-finder");
|
||||||
|
const { writeTsconfigSync } = require("./write-tsconfig");
|
||||||
|
|
||||||
|
const repoRoot = config.repoRoot;
|
||||||
|
const tscPath = path.join(repoRoot, "node_modules", "typescript", "bin", "tsc");
|
||||||
|
const tsconfigPath = path.join(repoRoot, config.targetTsconfig);
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log("## Initializing tsc --watch process...");
|
||||||
|
const tscWatchProcess = child_process.spawn("node", [tscPath, "-p", tsconfigPath, "--watch"]);
|
||||||
|
await waitForBuildComplete(tscWatchProcess);
|
||||||
|
|
||||||
|
const alreadyAttempted = new Set();
|
||||||
|
|
||||||
|
for (let pass = 1; ; pass += 1) {
|
||||||
|
let successesThisPass = 0;
|
||||||
|
const uncheckedLeafFiles = await getUncheckedLeafFiles();
|
||||||
|
const candidateFiles = uncheckedLeafFiles.filter((f) => !alreadyAttempted.has(f));
|
||||||
|
const candidateCount = candidateFiles.length;
|
||||||
|
console.log(`## Starting pass ${pass} with ${candidateCount} candidate files`);
|
||||||
|
|
||||||
|
for (const file of candidateFiles) {
|
||||||
|
alreadyAttempted.add(file);
|
||||||
|
if (await tryAutoAddStrictNulls(tscWatchProcess, tsconfigPath, file)) {
|
||||||
|
successesThisPass += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`### Finished pass ${pass} (added ${successesThisPass}/${candidateCount})`);
|
||||||
|
if (successesThisPass === 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("## Stopping tsc --watch process...");
|
||||||
|
tscWatchProcess.kill();
|
||||||
|
|
||||||
|
console.log('## Collapsing fully null-checked directories into "include" patterns...');
|
||||||
|
collapseCompletedDirectories(tsconfigPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function tryAutoAddStrictNulls(child, tsconfigPath, file) {
|
||||||
|
const relativeFilePath = path.relative(repoRoot, file).replace(/\\/g, "/");
|
||||||
|
const originalConfig = JSON.parse(fs.readFileSync(tsconfigPath).toString());
|
||||||
|
originalConfig.files = Array.from(new Set(originalConfig.files.sort()));
|
||||||
|
|
||||||
|
// Config on accept
|
||||||
|
const newConfig = Object.assign({}, originalConfig);
|
||||||
|
newConfig.files = Array.from(new Set(originalConfig.files.concat("./" + relativeFilePath).sort()));
|
||||||
|
|
||||||
|
const buildCompetePromise = waitForBuildComplete(child);
|
||||||
|
|
||||||
|
writeTsconfigSync(tsconfigPath, newConfig);
|
||||||
|
|
||||||
|
const errorCount = await buildCompetePromise;
|
||||||
|
const success = errorCount === 0;
|
||||||
|
if (success) {
|
||||||
|
console.log(`${relativeFilePath}: added`);
|
||||||
|
} else {
|
||||||
|
console.log(`${relativeFilePath}: ${errorCount} error(s), skipped`);
|
||||||
|
writeTsconfigSync(tsconfigPath, originalConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildCompletePattern = /Found (\d+) errors?\. Watching for file changes\./gi;
|
||||||
|
async function waitForBuildComplete(tscWatchProcess) {
|
||||||
|
const match = await waitForStdoutMatching(tscWatchProcess, buildCompletePattern);
|
||||||
|
const errorCount = +match[1];
|
||||||
|
return errorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function waitForStdoutMatching(child, pattern) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const listener = (data) => {
|
||||||
|
const textOut = data.toString();
|
||||||
|
const match = pattern.exec(textOut);
|
||||||
|
if (match) {
|
||||||
|
child.stdout.removeListener("data", listener);
|
||||||
|
resolve(match);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
child.stdout.on("data", listener);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(error.stack);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
83
strict-null-checks/collapse-completed-directories.js
Normal file
83
strict-null-checks/collapse-completed-directories.js
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const config = require("./config");
|
||||||
|
const { writeTsconfigSync } = require("./write-tsconfig");
|
||||||
|
|
||||||
|
const repoRoot = config.repoRoot;
|
||||||
|
|
||||||
|
function collapseCompletedDirectories(tsconfigPath) {
|
||||||
|
const tsconfigContent = JSON.parse(fs.readFileSync(tsconfigPath).toString());
|
||||||
|
const listedFiles = Array.from(new Set(tsconfigContent.files.sort()));
|
||||||
|
const listedIncludes = Array.from(new Set(tsconfigContent.include.sort()));
|
||||||
|
const listedDirectories = listedIncludes.map(includeToDirectory);
|
||||||
|
const completedSet = new Set([...listedFiles, ...listedDirectories]);
|
||||||
|
|
||||||
|
reduceCompletedSet(completedSet, "./src");
|
||||||
|
|
||||||
|
const completedPaths = Array.from(completedSet).sort();
|
||||||
|
tsconfigContent.files = completedPaths.filter(isTsFile);
|
||||||
|
tsconfigContent.include = completedPaths.filter(isSourceDirectory).map(directoryToInclude);
|
||||||
|
|
||||||
|
writeTsconfigSync(tsconfigPath, tsconfigContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert from src/common/styles/**/* to ./src/common/styles
|
||||||
|
function includeToDirectory(include) {
|
||||||
|
return "./" + include.replace("/**/*", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert from ./src/common/styles to src/common/styles/**/*
|
||||||
|
function directoryToInclude(directory) {
|
||||||
|
return directory.substring(2) + "/**/*";
|
||||||
|
}
|
||||||
|
|
||||||
|
function reduceCompletedSet(completedSet, root) {
|
||||||
|
if (completedSet.has(root)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!isSourceDirectory(root)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const children = listRelevantChildren(root);
|
||||||
|
let allChildrenReduced = true;
|
||||||
|
for (const child of children) {
|
||||||
|
const childReduced = reduceCompletedSet(completedSet, child);
|
||||||
|
allChildrenReduced = allChildrenReduced && childReduced;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allChildrenReduced) {
|
||||||
|
for (const child of children) {
|
||||||
|
completedSet.delete(child);
|
||||||
|
}
|
||||||
|
completedSet.add(root);
|
||||||
|
}
|
||||||
|
return allChildrenReduced;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSourceDirectory(relativePath) {
|
||||||
|
// this assumes directories don't have .s in their names, which isn't robust generally
|
||||||
|
// but happens to be true in our repo
|
||||||
|
const isDirectory = -1 === relativePath.indexOf(".", 1);
|
||||||
|
return isDirectory && !relativePath.includes("__snapshots__");
|
||||||
|
}
|
||||||
|
|
||||||
|
const isTsFileRegex = /\.(ts|tsx)$/;
|
||||||
|
function isTsFile(relativePath) {
|
||||||
|
return isTsFileRegex.test(relativePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
function listRelevantChildren(relativePath) {
|
||||||
|
const rawReaddir = fs.readdirSync(path.join(repoRoot, relativePath));
|
||||||
|
const directories = rawReaddir.filter(isSourceDirectory);
|
||||||
|
const tsFiles = rawReaddir.filter(isTsFile);
|
||||||
|
return [...directories, ...tsFiles].map((name) => relativePath + "/" + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
collapseCompletedDirectories,
|
||||||
|
};
|
||||||
11
strict-null-checks/config.js
Normal file
11
strict-null-checks/config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
const path = require("path");
|
||||||
|
const repoRoot = path.join(__dirname, "../").replace(/\\/g, "/");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
repoRoot: repoRoot,
|
||||||
|
srcRoot: `${repoRoot}/src`,
|
||||||
|
targetTsconfig: "tsconfig.strict.json",
|
||||||
|
skippedFiles: new Set([]),
|
||||||
|
};
|
||||||
70
strict-null-checks/eligible-file-finder.js
Normal file
70
strict-null-checks/eligible-file-finder.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const glob = require("glob");
|
||||||
|
const config = require("./config");
|
||||||
|
const { getMemoizedImportsForFile } = require("./import-finder");
|
||||||
|
|
||||||
|
// "Eligible" means "a file that we might want to list in tsconfig.strictNullChecks.json"
|
||||||
|
// "Checked" means "a file that is currently listed in tsconfig.strictNullChecks.json"
|
||||||
|
// It is possible for an ineligible file to be checked (eg, a png under /src/icons/**)
|
||||||
|
|
||||||
|
const isEligibleFile = (file) => !config.skippedFiles.has(path.relative(config.srcRoot, file));
|
||||||
|
|
||||||
|
function globAsync(pattern) {
|
||||||
|
return new Promise((resolve, reject) => glob(pattern, (err, files) => (err ? reject(err) : resolve(files))));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Includes both checked and unchecked files (ie, doesn't care about inclusion in tsconfig.strictNullChecks.json)
|
||||||
|
async function getAllEligibleFiles() {
|
||||||
|
const tsFiles = await globAsync(`${config.srcRoot}/**/*.@(ts|tsx)`);
|
||||||
|
return tsFiles.filter(isEligibleFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Includes ineligible files that are listed under glob patterns in tsconfig.strictNullChecks
|
||||||
|
async function getAllCheckedFiles() {
|
||||||
|
const tsconfigPath = path.join(config.repoRoot, config.targetTsconfig);
|
||||||
|
const tsconfigContent = JSON.parse(fs.readFileSync(tsconfigPath).toString());
|
||||||
|
|
||||||
|
const set = new Set(tsconfigContent.files.map((f) => path.join(config.repoRoot, f).replace(/\\/g, "/")));
|
||||||
|
await Promise.all(
|
||||||
|
tsconfigContent.include.map(async (include) => {
|
||||||
|
const includePath = path.join(config.repoRoot, include);
|
||||||
|
const files = await globAsync(includePath);
|
||||||
|
for (const file of files) {
|
||||||
|
set.add(file);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUncheckedLeafFiles() {
|
||||||
|
const checkedFiles = await getAllCheckedFiles();
|
||||||
|
const eligibleFiles = await getAllEligibleFiles();
|
||||||
|
const eligibleFileSet = new Set(eligibleFiles);
|
||||||
|
const allUncheckedFiles = eligibleFiles.filter((file) => !checkedFiles.has(file));
|
||||||
|
|
||||||
|
const areAllImportsChecked = (file) => {
|
||||||
|
const allImports = getMemoizedImportsForFile(file, config.srcRoot);
|
||||||
|
const uncheckedImports = allImports.filter((imp) => !checkedFiles.has(imp));
|
||||||
|
const ineligibleUncheckedImports = uncheckedImports.filter((imp) => !eligibleFileSet.has(imp));
|
||||||
|
if (ineligibleUncheckedImports.length > 0) {
|
||||||
|
console.warn(
|
||||||
|
`Eligible file ${file} with unchecked ineligible imports [${ineligibleUncheckedImports.join(", ")}]`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return uncheckedImports.length === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
return allUncheckedFiles.filter(areAllImportsChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getAllEligibleFiles,
|
||||||
|
getUncheckedLeafFiles,
|
||||||
|
getAllCheckedFiles,
|
||||||
|
};
|
||||||
63
strict-null-checks/find.js
Normal file
63
strict-null-checks/find.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
const path = require("path");
|
||||||
|
const process = require("process");
|
||||||
|
const { srcRoot } = require("./config");
|
||||||
|
const { getUncheckedLeafFiles, getAllEligibleFiles } = require("./eligible-file-finder");
|
||||||
|
const { getImportsForFile } = require("./import-finder");
|
||||||
|
|
||||||
|
if (process.argv.includes("--help")) {
|
||||||
|
console.log("yarn null:find [--sort=name|count] [--show-count] [--filter file_path_substring]");
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
const sortBy = process.argv.includes("--sort=name") ? "name" : "count";
|
||||||
|
const printDependedOnCount = process.argv.includes("--show-count");
|
||||||
|
const filterArgIndex = process.argv.indexOf("--filter") + 1;
|
||||||
|
const filterArg = filterArgIndex === 0 ? null : process.argv[filterArgIndex];
|
||||||
|
const filter = filterArg && ((file) => file.includes(filterArg));
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const eligibleFiles = await getUncheckedLeafFiles();
|
||||||
|
|
||||||
|
const eligibleSet = new Set(eligibleFiles);
|
||||||
|
|
||||||
|
const dependedOnCount = new Map(eligibleFiles.map((file) => [file, 0]));
|
||||||
|
|
||||||
|
for (const file of await getAllEligibleFiles()) {
|
||||||
|
if (eligibleSet.has(file)) {
|
||||||
|
// Already added
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const imp of getImportsForFile(file, srcRoot)) {
|
||||||
|
if (dependedOnCount.has(imp)) {
|
||||||
|
dependedOnCount.set(imp, dependedOnCount.get(imp) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let out = Array.from(dependedOnCount.entries());
|
||||||
|
if (filter) {
|
||||||
|
out = out.filter((x) => filter(x[0]));
|
||||||
|
}
|
||||||
|
if (sortBy === "count") {
|
||||||
|
out = out.sort((a, b) => b[1] - a[1]);
|
||||||
|
} else if (sortBy === "name") {
|
||||||
|
out = out.sort((a, b) => a[0].localeCompare(b[0]));
|
||||||
|
}
|
||||||
|
for (const pair of out) {
|
||||||
|
console.log(toFormattedFilePath(pair[0]) + (printDependedOnCount ? ` — Depended on by **${pair[1]}** files` : ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toFormattedFilePath(file) {
|
||||||
|
const relativePath = path.relative(srcRoot, file).replace(/\\/g, "/");
|
||||||
|
return `"./src/${relativePath}",`;
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error(error.stack);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
34
strict-null-checks/import-finder.js
Normal file
34
strict-null-checks/import-finder.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
const ts = require("typescript");
|
||||||
|
|
||||||
|
const imports = new Map();
|
||||||
|
const getMemoizedImportsForFile = (file, srcRoot) => {
|
||||||
|
if (imports.has(file)) {
|
||||||
|
return imports.get(file);
|
||||||
|
}
|
||||||
|
const importList = getImportsForFile(file, srcRoot);
|
||||||
|
imports.set(file, importList);
|
||||||
|
return importList;
|
||||||
|
};
|
||||||
|
|
||||||
|
function getImportsForFile(parent, srcRoot) {
|
||||||
|
return ts
|
||||||
|
.preProcessFile(fs.readFileSync(parent).toString())
|
||||||
|
.importedFiles.map(({ fileName }) => fileName)
|
||||||
|
.filter((base) => /\//.test(base)) // remove node modules (the import must contain '/')
|
||||||
|
.map((base) => (/(^\.\/)|(^\.\.\/)/.test(base) ? path.join(path.dirname(parent), base) : path.join(srcRoot, base)))
|
||||||
|
.map((base) => (fs.existsSync(base) ? path.join(base, "index") : base))
|
||||||
|
.map((base) => base.replace(/\\/g, "/"))
|
||||||
|
.map((base) => ["ts", "tsx", "d.ts", "js", "jsx"].map((ext) => `${base}.${ext}`).find(fs.existsSync))
|
||||||
|
.filter((base) => base && base !== parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getImportsForFile,
|
||||||
|
getMemoizedImportsForFile,
|
||||||
|
};
|
||||||
12
strict-null-checks/write-tsconfig.js
Normal file
12
strict-null-checks/write-tsconfig.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
// Licensed under the MIT License.
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
writeTsconfigSync: (tsconfigPath, content) => {
|
||||||
|
let serializedContent = JSON.stringify(content, null, " ");
|
||||||
|
serializedContent += "\n";
|
||||||
|
|
||||||
|
fs.writeFileSync(tsconfigPath, serializedContent);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -15,107 +15,111 @@
|
|||||||
"./src/Common/DocumentUtility.ts",
|
"./src/Common/DocumentUtility.ts",
|
||||||
"./src/Common/EnvironmentUtility.ts",
|
"./src/Common/EnvironmentUtility.ts",
|
||||||
"./src/Common/HashMap.ts",
|
"./src/Common/HashMap.ts",
|
||||||
|
"./src/Common/HeadersUtility.test.ts",
|
||||||
"./src/Common/HeadersUtility.ts",
|
"./src/Common/HeadersUtility.ts",
|
||||||
"./src/Common/Logger.ts",
|
"./src/Common/Logger.ts",
|
||||||
|
"./src/Common/MessageHandler.test.ts",
|
||||||
"./src/Common/MessageHandler.ts",
|
"./src/Common/MessageHandler.ts",
|
||||||
"./src/Common/MongoUtility.ts",
|
"./src/Common/MongoUtility.ts",
|
||||||
|
"./src/Common/ObjectCache.test.ts",
|
||||||
"./src/Common/ObjectCache.ts",
|
"./src/Common/ObjectCache.ts",
|
||||||
|
"./src/Common/OfferUtility.test.ts",
|
||||||
"./src/Common/OfferUtility.ts",
|
"./src/Common/OfferUtility.ts",
|
||||||
|
"./src/Common/Splitter.ts",
|
||||||
"./src/Common/ThemeUtility.ts",
|
"./src/Common/ThemeUtility.ts",
|
||||||
"./src/Common/UrlUtility.ts",
|
"./src/Common/UrlUtility.ts",
|
||||||
"./src/Common/Splitter.ts",
|
|
||||||
"./src/ConfigContext.ts",
|
"./src/ConfigContext.ts",
|
||||||
"./src/Contracts/ActionContracts.ts",
|
"./src/Contracts/ActionContracts.ts",
|
||||||
"./src/Contracts/DataModels.ts",
|
"./src/Contracts/DataModels.ts",
|
||||||
"./src/Contracts/Diagnostics.ts",
|
"./src/Contracts/Diagnostics.ts",
|
||||||
"./src/Contracts/ExplorerContracts.ts",
|
"./src/Contracts/ExplorerContracts.ts",
|
||||||
|
"./src/Contracts/SelfServeContracts.ts",
|
||||||
"./src/Contracts/SubscriptionType.ts",
|
"./src/Contracts/SubscriptionType.ts",
|
||||||
"./src/Contracts/Versions.ts",
|
"./src/Contracts/Versions.ts",
|
||||||
"./src/Controls/Heatmap/Heatmap.ts",
|
|
||||||
"./src/Controls/Heatmap/HeatmapDatatypes.ts",
|
|
||||||
"./src/DefaultAccountExperienceType.ts",
|
"./src/DefaultAccountExperienceType.ts",
|
||||||
"./src/Definitions/globals.d.ts",
|
|
||||||
"./src/Definitions/html.d.ts",
|
|
||||||
"./src/Definitions/jquery-ui.d.ts",
|
|
||||||
"./src/Definitions/jquery.d.ts",
|
|
||||||
"./src/Definitions/plotly.js-cartesian-dist.d-min.ts",
|
|
||||||
"./src/Definitions/svg.d.ts",
|
|
||||||
"./src/Explorer/Controls/ErrorDisplayComponent/ErrorDisplayComponent.ts",
|
|
||||||
"./src/Explorer/Controls/GitHub/GitHubStyleConstants.ts",
|
"./src/Explorer/Controls/GitHub/GitHubStyleConstants.ts",
|
||||||
"./src/Explorer/Controls/InputTypeahead/InputTypeahead.ts",
|
"./src/Explorer/Controls/InputTypeahead/InputTypeahead.ts",
|
||||||
"./src/Explorer/Controls/SmartUi/InputUtils.ts",
|
"./src/Explorer/Controls/SmartUi/InputUtils.ts",
|
||||||
"./src/Explorer/Graph/GraphExplorerComponent/__mocks__/GremlinClient.ts",
|
"./src/Explorer/Graph/GraphExplorerComponent/ArraysByKeyCache.test.ts",
|
||||||
"./src/Explorer/Graph/GraphExplorerComponent/ArraysByKeyCache.ts",
|
"./src/Explorer/Graph/GraphExplorerComponent/ArraysByKeyCache.ts",
|
||||||
"./src/Explorer/Graph/GraphExplorerComponent/EdgeInfoCache.ts",
|
"./src/Explorer/Graph/GraphExplorerComponent/EdgeInfoCache.ts",
|
||||||
"./src/Explorer/Graph/GraphExplorerComponent/GraphData.ts",
|
"./src/Explorer/Graph/GraphExplorerComponent/GraphData.ts",
|
||||||
"./src/Explorer/Notebook/NotebookComponent/__mocks__/rx-jupyter.ts",
|
|
||||||
"./src/Explorer/Notebook/FileSystemUtil.ts",
|
"./src/Explorer/Notebook/FileSystemUtil.ts",
|
||||||
"./src/Explorer/Notebook/NTeractUtil.ts",
|
"./src/Explorer/Notebook/NTeractUtil.ts",
|
||||||
"./src/Explorer/Notebook/NotebookComponent/actions.ts",
|
"./src/Explorer/Notebook/NotebookComponent/actions.ts",
|
||||||
"./src/Explorer/Notebook/NotebookComponent/loadTransform.ts",
|
"./src/Explorer/Notebook/NotebookComponent/loadTransform.ts",
|
||||||
"./src/Explorer/Notebook/NotebookComponent/reducers.ts",
|
"./src/Explorer/Notebook/NotebookComponent/reducers.ts",
|
||||||
"./src/Explorer/Notebook/NotebookComponent/types.ts",
|
"./src/Explorer/Notebook/NotebookComponent/types.ts",
|
||||||
|
"./src/Explorer/Notebook/NotebookContentClient.ts",
|
||||||
"./src/Explorer/Notebook/NotebookContentItem.ts",
|
"./src/Explorer/Notebook/NotebookContentItem.ts",
|
||||||
|
"./src/Explorer/Notebook/NotebookRenderer/AzureTheme.tsx",
|
||||||
|
"./src/Explorer/Notebook/NotebookRenderer/decorators/CellCreator.tsx",
|
||||||
"./src/Explorer/Notebook/NotebookUtil.ts",
|
"./src/Explorer/Notebook/NotebookUtil.ts",
|
||||||
"./src/Explorer/Tree/AccessibleVerticalList.ts",
|
|
||||||
"./src/Explorer/Panes/PaneComponents.ts",
|
"./src/Explorer/Panes/PaneComponents.ts",
|
||||||
|
"./src/Explorer/Panes/PanelFooterComponent.tsx",
|
||||||
|
"./src/Explorer/Panes/PanelLoadingScreen.tsx",
|
||||||
"./src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts",
|
"./src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts",
|
||||||
"./src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts",
|
"./src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts",
|
||||||
"./src/Explorer/Tables/Constants.ts",
|
"./src/Explorer/Tables/Constants.ts",
|
||||||
"./src/Explorer/Tables/CqlUtilities.ts",
|
"./src/Explorer/Tables/CqlUtilities.ts",
|
||||||
"./src/Explorer/Tables/QueryBuilder/DateTimeUtilities.ts",
|
|
||||||
"./src/Explorer/Tables/DataTable/CacheBase.ts",
|
"./src/Explorer/Tables/DataTable/CacheBase.ts",
|
||||||
"./src/Explorer/Tables/Entities.ts",
|
"./src/Explorer/Tables/Entities.ts",
|
||||||
"./src/Explorer/Notebook/NotebookComponent/__mocks__/rx-jupyter.ts",
|
"./src/Explorer/Tables/QueryBuilder/DateTimeUtilities.test.ts",
|
||||||
"./src/Explorer/Notebook/NotebookContentClient.ts",
|
"./src/Explorer/Tables/QueryBuilder/DateTimeUtilities.ts",
|
||||||
|
"./src/Explorer/Tree/AccessibleVerticalList.ts",
|
||||||
"./src/GitHub/GitHubConnector.ts",
|
"./src/GitHub/GitHubConnector.ts",
|
||||||
|
"./src/HostedExplorerChildFrame.ts",
|
||||||
"./src/Index.ts",
|
"./src/Index.ts",
|
||||||
"./src/NotebookWorkspaceManager/NotebookWorkspaceResourceProviderMockClients.ts",
|
"./src/NotebookWorkspaceManager/NotebookWorkspaceResourceProviderMockClients.ts",
|
||||||
|
"./src/Platform/Hosted/Components/SignInButton.tsx",
|
||||||
|
"./src/Platform/Hosted/extractFeatures.test.ts",
|
||||||
|
"./src/Platform/Hosted/extractFeatures.ts",
|
||||||
"./src/ReactDevTools.ts",
|
"./src/ReactDevTools.ts",
|
||||||
"./src/ResourceProvider/IResourceProviderClient.ts",
|
"./src/ResourceProvider/IResourceProviderClient.ts",
|
||||||
|
"./src/SelfServe/SelfServeStyles.tsx",
|
||||||
|
"./src/SelfServe/SqlX/SqlxTypes.ts",
|
||||||
"./src/Shared/Constants.ts",
|
"./src/Shared/Constants.ts",
|
||||||
|
"./src/Shared/DefaultExperienceUtility.ts",
|
||||||
"./src/Shared/ExplorerSettings.ts",
|
"./src/Shared/ExplorerSettings.ts",
|
||||||
"./src/Shared/PriceEstimateCalculator.ts",
|
"./src/Shared/PriceEstimateCalculator.ts",
|
||||||
|
"./src/Shared/StorageUtility.test.ts",
|
||||||
"./src/Shared/StorageUtility.ts",
|
"./src/Shared/StorageUtility.ts",
|
||||||
|
"./src/Shared/StringUtility.test.ts",
|
||||||
"./src/Shared/StringUtility.ts",
|
"./src/Shared/StringUtility.ts",
|
||||||
"./src/Shared/Telemetry/TelemetryConstants.ts",
|
|
||||||
"./src/Shared/Telemetry/TelemetryProcessor.ts",
|
|
||||||
"./src/Shared/appInsights.ts",
|
"./src/Shared/appInsights.ts",
|
||||||
"./src/Shared/DefaultExperienceUtility.ts",
|
|
||||||
"./src/Terminal/index.ts",
|
|
||||||
"./src/Terminal/JupyterLabAppFactory.ts",
|
|
||||||
"./src/UserContext.ts",
|
"./src/UserContext.ts",
|
||||||
|
"./src/Utils/AutoPilotUtils.ts",
|
||||||
|
"./src/Utils/Base64Utils.test.ts",
|
||||||
"./src/Utils/Base64Utils.ts",
|
"./src/Utils/Base64Utils.ts",
|
||||||
"./src/Utils/BlobUtils.ts",
|
"./src/Utils/BlobUtils.ts",
|
||||||
|
"./src/Utils/GitHubUtils.test.ts",
|
||||||
"./src/Utils/GitHubUtils.ts",
|
"./src/Utils/GitHubUtils.ts",
|
||||||
|
"./src/Utils/MessageValidation.test.ts",
|
||||||
"./src/Utils/MessageValidation.ts",
|
"./src/Utils/MessageValidation.ts",
|
||||||
"./src/Utils/StringUtils.ts",
|
|
||||||
"./src/Utils/WindowUtils.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/types.ts",
|
|
||||||
"./src/Utils/AutoPilotUtils.ts",
|
|
||||||
"./src/Utils/PricingUtils.ts",
|
"./src/Utils/PricingUtils.ts",
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/cassandraResources.ts",
|
"./src/Utils/StringUtils.ts",
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/collection.ts",
|
"./src/Utils/WindowUtils.test.ts",
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/collectionPartition.ts",
|
"./src/Utils/WindowUtils.ts",
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/collectionPartitionRegion.ts",
|
"./src/hooks/useDirectories.tsx",
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/collectionRegion.ts",
|
"./src/i18n.ts",
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/database.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/databaseAccountRegion.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/databaseAccounts.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/gremlinResources.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/mongoDBResources.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/operations.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/partitionKeyRangeId.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/partitionKeyRangeIdRegion.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/percentile.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/percentileSourceTarget.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/percentileTarget.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/sqlResources.ts",
|
|
||||||
"./src/Utils/arm/generatedClients/2020-04-01/tableResources.ts",
|
|
||||||
"./src/Utils/arm/request.ts",
|
|
||||||
"./src/quickstart.ts",
|
"./src/quickstart.ts",
|
||||||
"./src/setupTests.ts",
|
"./src/setupTests.ts",
|
||||||
|
"./src/userContext.test.ts",
|
||||||
"./src/workers/upload/definitions.ts"
|
"./src/workers/upload/definitions.ts"
|
||||||
],
|
],
|
||||||
"include": []
|
"include": [
|
||||||
|
"src/Controls/**/*",
|
||||||
|
"src/Definitions/**/*",
|
||||||
|
"src/Explorer/Controls/ErrorDisplayComponent/**/*",
|
||||||
|
"src/Explorer/Controls/RadioSwitchComponent/**/*",
|
||||||
|
"src/Explorer/Controls/ResizeSensorReactComponent/**/*",
|
||||||
|
"src/Explorer/Graph/GraphExplorerComponent/__mocks__/**/*",
|
||||||
|
"src/Explorer/Notebook/NotebookComponent/__mocks__/**/*",
|
||||||
|
"src/Libs/**/*",
|
||||||
|
"src/Localization/**/*",
|
||||||
|
"src/Platform/Emulator/**/*",
|
||||||
|
"src/Shared/Telemetry/**/*",
|
||||||
|
"src/Terminal/**/*",
|
||||||
|
"src/Utils/arm/**/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user