Compare commits

..

2 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
752fe5259d Initial plan 2026-01-19 13:08:04 +00:00
Sakshi Gupta
b8bf30551d updated the text 2026-01-19 18:35:48 +05:30
111 changed files with 11876 additions and 12370 deletions

View File

@@ -6,8 +6,8 @@ on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
schedule:
# Once every day at 7 AM PST
- cron: "0 13 * * *"
# Once every two hours
- cron: "0 */2 * * *"
permissions:
id-token: write

1
.gitignore vendored
View File

@@ -17,7 +17,6 @@ Contracts/*
failure.png
screenshots/*
GettingStarted-ignore*.ipynb
src/Localization/Keys.generated.ts
/test-results/
/playwright-report/
/blob-report/

14305
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"description": "Cosmos Explorer",
"main": "index.js",
"dependencies": {
"@azure/arm-cosmosdb": "16.4.0",
"@azure/arm-cosmosdb": "9.1.0",
"@azure/cosmos": "4.7.0",
"@azure/cosmos-language-service": "0.0.5",
"@azure/identity": "4.5.0",
@@ -14,12 +14,12 @@
"@fluentui/react": "8.119.0",
"@fluentui/react-components": "9.54.2",
"@jupyterlab/services": "6.0.2",
"@jupyterlab/terminal": "3.6.8",
"@jupyterlab/terminal": "3.0.3",
"@microsoft/applicationinsights-web": "2.6.1",
"@nteract/commutable": "7.5.1",
"@nteract/connected-components": "6.8.2",
"@nteract/core": "15.1.9",
"@nteract/data-explorer": "8.2.12",
"@nteract/data-explorer": "8.0.3",
"@nteract/directory-listing": "2.0.6",
"@nteract/dropdown-menu": "1.0.1",
"@nteract/editor": "10.1.12",
@@ -31,7 +31,7 @@
"@nteract/monaco-editor": "3.2.2",
"@nteract/octicons": "2.0.0",
"@nteract/outputs": "3.0.9",
"@nteract/presentational-components": "3.4.12",
"@nteract/presentational-components": "3.0.7",
"@nteract/stateful-components": "1.7.0",
"@nteract/styles": "2.0.2",
"@nteract/transform-geojson": "5.1.8",
@@ -39,26 +39,25 @@
"@nteract/transform-plotly": "6.1.6",
"@nteract/transform-vdom": "4.0.11",
"@nteract/transform-vega": "7.0.6",
"@octokit/request": "8.4.1",
"@octokit/rest": "17.9.2",
"@phosphor/widgets": "1.9.3",
"@testing-library/jest-dom": "6.4.6",
"@types/lodash": "4.14.171",
"@types/mkdirp": "1.0.1",
"@types/node-fetch": "2.6.13",
"@types/node-fetch": "2.5.7",
"@xmldom/xmldom": "0.7.13",
"@xterm/addon-fit": "0.10.0",
"@xterm/xterm": "5.5.0",
"allotment": "1.20.2",
"applicationinsights": "1.8.0",
"bootstrap": "3.4.1",
"canvas": "3.2.1",
"canvas": "2.11.2",
"clean-webpack-plugin": "4.0.0",
"clipboard-copy": "4.0.1",
"copy-webpack-plugin": "11.0.0",
"crossroads": "0.12.2",
"css-element-queries": "1.1.1",
"d3": "7.9.0",
"d3": "7.8.5",
"datatables.net-colreorder-dt": "1.7.0",
"datatables.net-dt": "1.13.8",
"date-fns": "1.29.0",
@@ -71,8 +70,7 @@
"html2canvas": "1.0.0-rc.5",
"i18next": "23.11.5",
"i18next-browser-languagedetector": "6.0.1",
"i18next-http-backend": "3.0.2",
"i18next-resources-to-backend": "1.2.1",
"i18next-http-backend": "1.0.23",
"iframe-resizer-react": "1.1.0",
"immer": "9.0.6",
"immutable": "4.0.0-rc.12",
@@ -81,15 +79,12 @@
"jquery-typeahead": "2.11.1",
"jquery-ui-dist": "1.13.2",
"knockout": "3.5.1",
"lodash": "4.17.23",
"lodash-es": "4.17.23",
"min-document": "2.19.1",
"loader-utils": "2.0.3",
"mkdirp": "1.0.4",
"monaco-editor": "0.44.0",
"ms": "2.1.3",
"nanoid": "3.3.8",
"p-retry": "6.2.1",
"patch-package": "8.0.1",
"patch-package": "8.0.0",
"plotly.js-cartesian-dist-min": "1.52.3",
"post-robot": "10.0.42",
"q": "1.5.1",
@@ -108,6 +103,7 @@
"react-youtube": "9.0.1",
"reflect-metadata": "0.1.13",
"rx-jupyter": "5.5.12",
"sanitize-html": "2.3.3",
"shell-quote": "1.7.3",
"styled-components": "5.0.1",
"swr": "0.4.0",
@@ -115,30 +111,16 @@
"tinykeys": "2.1.0",
"underscore": "1.12.1",
"utility-types": "3.10.0",
"uuid": "9.0.0",
"web-vitals": "4.2.4",
"ws": "8.17.1",
"uuid": "9.0.0",
"zustand": "3.5.0"
},
"overrides": {
"d3-color": "3.1.0",
"cross-spawn": "7.0.6",
"less-vars-loader": {
"json5": "1.0.2"
},
"trim": "0.0.3",
"@octokit/plugin-paginate-rest": "9.2.2",
"@octokit/request-error": "5.1.1",
"@octokit/request": "8.4.1",
"prismjs": "1.30.0",
"sanitize-html": "2.17.0"
},
"devDependencies": {
"@babel/core": "7.29.0",
"@babel/core": "7.24.7",
"@babel/preset-env": "7.24.7",
"@babel/preset-react": "7.24.7",
"@babel/preset-typescript": "7.24.7",
"@playwright/test": "1.55.1",
"@playwright/test": "1.49.1",
"@testing-library/react": "11.2.3",
"@types/applicationinsights-js": "1.0.7",
"@types/codemirror": "0.0.56",
@@ -152,7 +134,7 @@
"@types/hasher": "0.0.31",
"@types/jest": "29.5.12",
"@types/jquery": "3.5.29",
"@types/node": "18.19.0",
"@types/node": "12.11.1",
"@types/post-robot": "10.0.1",
"@types/q": "1.5.1",
"@types/react": "17.0.44",
@@ -163,7 +145,7 @@
"@types/react-window": "1.8.8",
"@types/sanitize-html": "1.27.2",
"@types/sinon": "2.3.3",
"@types/styled-components": "5.1.32",
"@types/styled-components": "5.1.1",
"@types/underscore": "1.7.36",
"@types/youtube-player": "5.5.6",
"@typescript-eslint/eslint-plugin": "6.7.4",
@@ -171,7 +153,6 @@
"@webpack-cli/serve": "2.0.5",
"babel-jest": "29.7.0",
"babel-loader": "8.1.0",
"brace-expansion": "1.1.12",
"buffer": "5.1.0",
"case-sensitive-paths-webpack-plugin": "2.4.0",
"create-file-webpack": "1.0.2",
@@ -189,7 +170,6 @@
"html-inline-css-webpack-plugin": "1.11.2",
"html-loader": "5.0.0",
"html-webpack-plugin": "5.5.3",
"i18next-resources-for-ts": "2.0.0",
"jest": "29.7.0",
"jest-canvas-mock": "2.5.2",
"jest-circus": "29.7.0",
@@ -197,8 +177,7 @@
"jest-html-loader": "1.0.0",
"jest-react-hooks-shallow": "1.5.1",
"jest-trx-results-processor": "3.0.2",
"js-yaml": "3.14.2",
"less": "4.5.1",
"less": "3.8.1",
"less-loader": "11.1.3",
"less-vars-loader": "1.1.0",
"mini-css-extract-plugin": "2.1.0",
@@ -216,17 +195,14 @@
"typedoc": "0.26.2",
"typescript": "4.9.5",
"url-loader": "4.1.1",
"values-to-keys": "1.1.0",
"wait-on": "9.0.3",
"webpack": "5.104.1",
"webpack-bundle-analyzer": "5.2.0",
"wait-on": "4.0.2",
"webpack": "5.88.2",
"webpack-bundle-analyzer": "4.9.1",
"webpack-cli": "5.1.4",
"webpack-dev-server": "5.2.3",
"ws": "8.17.1"
"webpack-dev-server": "4.15.2"
},
"scripts": {
"postinstall": "patch-package && npm run generate:i18n-keys",
"prestart": "npm run generate:i18n-keys",
"postinstall": "patch-package",
"start": "webpack serve --mode development",
"dev": "echo \"WARNING: npm run dev has been deprecated\" && npm run build",
"build:dataExplorer:ci": "npm run build:ci",
@@ -253,7 +229,6 @@
"strict:find": "node ./strict-null-checks/find.js",
"strict:add": "node ./strict-null-checks/auto-add.js",
"compile:fullStrict": "tsc -p ./tsconfig.json --strictNullChecks",
"generate:i18n-keys": "node utils/generateI18nKeys.mjs",
"generateARMClients": "npx ts-node utils/armClientGenerator/generator.ts"
},
"repository": {

View File

@@ -26,6 +26,15 @@ export default defineConfig({
},
projects: [
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
launchOptions: {
args: ["--disable-web-security", "--disable-features=IsolateOrigins,site-per-process"],
},
},
},
{
name: "firefox",
use: {

View File

@@ -8,10 +8,9 @@
"name": "cosmos-explorer-preview",
"version": "1.0.0",
"dependencies": {
"body-parser": "^2.2.2",
"express": "^5.2.1",
"follow-redirects": "^1.15.6",
"http-proxy-middleware": "^3.0.5",
"body-parser": "^1.20.3",
"express": "^4.21.2",
"http-proxy-middleware": "^3.0.3",
"node": "^20.19.5",
"node-fetch": "^2.6.1",
"path-to-regexp": "^0.1.12"
@@ -19,7 +18,8 @@
},
"node_modules/@types/http-proxy": {
"version": "1.17.16",
"license": "MIT",
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.16.tgz",
"integrity": "sha512-sdWoUajOB1cd0A8cRRQ1cfyWNbmFKLAqBB89Y8x5iYyG/mkJHc0YUH8pdWBy2omi9qtCpiIgGjuwO0dQST2l5w==",
"dependencies": {
"@types/node": "*"
}
@@ -29,40 +29,50 @@
"license": "MIT"
},
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
"version": "1.3.8",
"license": "MIT",
"dependencies": {
"mime-types": "^3.0.0",
"negotiator": "^1.0.0"
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/body-parser": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz",
"integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==",
"version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"dependencies": {
"bytes": "^3.1.2",
"content-type": "^1.0.5",
"debug": "^4.4.3",
"http-errors": "^2.0.0",
"iconv-lite": "^0.7.0",
"on-finished": "^2.4.1",
"qs": "^6.14.1",
"raw-body": "^3.0.1",
"type-is": "^2.0.1"
"bytes": "3.1.2",
"content-type": "~1.0.5",
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"on-finished": "2.4.1",
"qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/body-parser/node_modules/debug": {
"version": "2.6.9",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/body-parser/node_modules/ms": {
"version": "2.0.0",
"license": "MIT"
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -73,7 +83,8 @@
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"license": "MIT",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
@@ -84,7 +95,8 @@
},
"node_modules/call-bound": {
"version": "1.0.4",
"license": "MIT",
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"get-intrinsic": "^1.3.0"
@@ -97,15 +109,13 @@
}
},
"node_modules/content-disposition": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
"integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
"engines": {
"node": ">=18"
"version": "0.5.4",
"license": "MIT",
"dependencies": {
"safe-buffer": "5.2.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
"engines": {
"node": ">= 0.6"
}
},
"node_modules/content-type": {
@@ -117,22 +127,20 @@
},
"node_modules/cookie": {
"version": "0.7.1",
"license": "MIT",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/cookie-signature": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
"engines": {
"node": ">=6.6.0"
}
"version": "1.0.6",
"license": "MIT"
},
"node_modules/debug": {
"version": "4.4.3",
"license": "MIT",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dependencies": {
"ms": "^2.1.3"
},
@@ -152,9 +160,18 @@
"node": ">= 0.8"
}
},
"node_modules/destroy": {
"version": "1.2.0",
"license": "MIT",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"license": "MIT",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
@@ -178,21 +195,24 @@
},
"node_modules/es-define-property": {
"version": "1.0.1",
"license": "MIT",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"license": "MIT",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dependencies": {
"es-errors": "^1.3.0"
},
@@ -218,77 +238,104 @@
"license": "MIT"
},
"node_modules/express": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz",
"integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==",
"version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"dependencies": {
"accepts": "^2.0.0",
"body-parser": "^2.2.1",
"content-disposition": "^1.0.0",
"content-type": "^1.0.5",
"cookie": "^0.7.1",
"cookie-signature": "^1.2.1",
"debug": "^4.4.0",
"depd": "^2.0.0",
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"etag": "^1.8.1",
"finalhandler": "^2.1.0",
"fresh": "^2.0.0",
"http-errors": "^2.0.0",
"merge-descriptors": "^2.0.0",
"mime-types": "^3.0.0",
"on-finished": "^2.4.1",
"once": "^1.4.0",
"parseurl": "^1.3.3",
"proxy-addr": "^2.0.7",
"qs": "^6.14.0",
"range-parser": "^1.2.1",
"router": "^2.2.0",
"send": "^1.1.0",
"serve-static": "^2.2.0",
"statuses": "^2.0.1",
"type-is": "^2.0.1",
"vary": "^1.1.2"
"accepts": "~1.3.8",
"array-flatten": "1.1.1",
"body-parser": "1.20.3",
"content-disposition": "0.5.4",
"content-type": "~1.0.4",
"cookie": "0.7.1",
"cookie-signature": "1.0.6",
"debug": "2.6.9",
"depd": "2.0.0",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"finalhandler": "1.3.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"merge-descriptors": "1.0.3",
"methods": "~1.1.2",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"path-to-regexp": "0.1.12",
"proxy-addr": "~2.0.7",
"qs": "6.13.0",
"range-parser": "~1.2.1",
"safe-buffer": "5.2.1",
"send": "0.19.0",
"serve-static": "1.16.2",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
},
"engines": {
"node": ">= 18"
"node": ">= 0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/express/node_modules/array-flatten": {
"version": "1.1.1",
"license": "MIT"
},
"node_modules/express/node_modules/debug": {
"version": "2.6.9",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/express/node_modules/ms": {
"version": "2.0.0",
"license": "MIT"
},
"node_modules/finalhandler": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz",
"integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==",
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"dependencies": {
"debug": "^4.4.0",
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"on-finished": "^2.4.1",
"parseurl": "^1.3.3",
"statuses": "^2.0.1"
"debug": "2.6.9",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"statuses": "2.0.1",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
"node": ">= 0.8"
}
},
"node_modules/finalhandler/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/finalhandler/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/follow-redirects": {
"version": "1.15.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz",
"integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==",
"version": "1.15.3",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
@@ -306,23 +353,25 @@
}
},
"node_modules/fresh": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"engines": {
"node": ">= 0.8"
"node": ">= 0.6"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"license": "MIT",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
@@ -344,7 +393,8 @@
},
"node_modules/get-proto": {
"version": "1.0.1",
"license": "MIT",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
@@ -355,7 +405,8 @@
},
"node_modules/gopd": {
"version": "1.2.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"engines": {
"node": ">= 0.4"
},
@@ -365,7 +416,8 @@
},
"node_modules/has-symbols": {
"version": "1.1.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"engines": {
"node": ">= 0.4"
},
@@ -375,7 +427,8 @@
},
"node_modules/hasown": {
"version": "2.0.2",
"license": "MIT",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dependencies": {
"function-bind": "^1.1.2"
},
@@ -384,22 +437,17 @@
}
},
"node_modules/http-errors": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
"version": "2.0.0",
"license": "MIT",
"dependencies": {
"depd": "~2.0.0",
"inherits": "~2.0.4",
"setprototypeof": "~1.2.0",
"statuses": "~2.0.2",
"toidentifier": "~1.0.1"
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/http-proxy": {
@@ -432,7 +480,8 @@
},
"node_modules/http-proxy-middleware/node_modules/braces": {
"version": "3.0.3",
"license": "MIT",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
"fill-range": "^7.1.1"
},
@@ -442,7 +491,8 @@
},
"node_modules/http-proxy-middleware/node_modules/fill-range": {
"version": "7.1.1",
"license": "MIT",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -452,14 +502,16 @@
},
"node_modules/http-proxy-middleware/node_modules/is-number": {
"version": "7.0.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/http-proxy-middleware/node_modules/micromatch": {
"version": "4.0.8",
"license": "MIT",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
@@ -470,7 +522,8 @@
},
"node_modules/http-proxy-middleware/node_modules/to-regex-range": {
"version": "5.0.1",
"license": "MIT",
"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"
},
@@ -479,18 +532,14 @@
}
},
"node_modules/iconv-lite": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
"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.0.0"
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/inherits": {
@@ -521,58 +570,62 @@
"node": ">=0.10.0"
}
},
"node_modules/is-promise": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/media-typer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
"version": "0.3.0",
"license": "MIT",
"engines": {
"node": ">= 0.8"
"node": ">= 0.6"
}
},
"node_modules/merge-descriptors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
"engines": {
"node": ">=18"
},
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/methods": {
"version": "1.1.2",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"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.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"version": "1.52.0",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
"version": "2.1.35",
"license": "MIT",
"dependencies": {
"mime-db": "^1.54.0"
"mime-db": "1.52.0"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
"node": ">= 0.6"
}
},
"node_modules/ms": {
@@ -580,27 +633,32 @@
"license": "MIT"
},
"node_modules/negotiator": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
"version": "0.6.3",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/node": {
"version": "20.19.5",
"resolved": "https://registry.npmjs.org/node/-/node-20.19.5.tgz",
"integrity": "sha512-9fJOHEP8AVrwpbhlUxnbudW8IbkseQVxl4yNQyI/rDfP+gNwKEmfPtBc/Luyf677i5Y0HKIBHiApiB9S9vvxKw==",
"hasInstallScript": true,
"license": "ISC",
"dependencies": {
"node-bin-setup": "^1.0.0"
},
"bin": {
"node": "bin/node.exe"
"node": "bin/node"
},
"engines": {
"npm": ">=5.0.0"
}
},
"node_modules/node-bin-setup": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/node-bin-setup/-/node-bin-setup-1.1.4.tgz",
"integrity": "sha512-vWNHOne0ZUavArqPP5LJta50+S8R261Fr5SvGul37HbEDcowvLjwdvd0ZeSr0r2lTSrPxl6okq9QUw8BFGiAxA=="
},
"node_modules/node-fetch": {
"version": "2.6.7",
"license": "MIT",
@@ -619,13 +677,10 @@
}
}
},
"node_modules/node/node_modules/node-bin-setup": {
"version": "1.1.4",
"license": "ISC"
},
"node_modules/object-inspect": {
"version": "1.13.4",
"license": "MIT",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
"engines": {
"node": ">= 0.4"
},
@@ -643,14 +698,6 @@
"node": ">= 0.8"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -661,7 +708,8 @@
},
"node_modules/path-to-regexp": {
"version": "0.1.12",
"license": "MIT"
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -692,10 +740,11 @@
}
},
"node_modules/qs": {
"version": "6.14.1",
"license": "BSD-3-Clause",
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"dependencies": {
"side-channel": "^1.1.0"
"side-channel": "^1.0.6"
},
"engines": {
"node": ">=0.6"
@@ -713,46 +762,40 @@
}
},
"node_modules/raw-body": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"dependencies": {
"bytes": "~3.1.2",
"http-errors": "~2.0.1",
"iconv-lite": "~0.7.0",
"unpipe": "~1.0.0"
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.10"
"node": ">= 0.8"
}
},
"node_modules/requires-port": {
"version": "1.0.0",
"license": "MIT"
},
"node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
"dependencies": {
"debug": "^4.4.0",
"depd": "^2.0.0",
"is-promise": "^4.0.0",
"parseurl": "^1.3.3",
"path-to-regexp": "^8.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/router/node_modules/path-to-regexp": {
"version": "8.3.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
"node_modules/safe-buffer": {
"version": "5.2.1",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/safer-buffer": {
"version": "2.1.2",
@@ -760,46 +803,61 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/send": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz",
"integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==",
"version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"dependencies": {
"debug": "^4.4.3",
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"etag": "^1.8.1",
"fresh": "^2.0.0",
"http-errors": "^2.0.1",
"mime-types": "^3.0.2",
"ms": "^2.1.3",
"on-finished": "^2.4.1",
"range-parser": "^1.2.1",
"statuses": "^2.0.2"
"debug": "2.6.9",
"depd": "2.0.0",
"destroy": "1.2.0",
"encodeurl": "~1.0.2",
"escape-html": "~1.0.3",
"etag": "~1.8.1",
"fresh": "0.5.2",
"http-errors": "2.0.0",
"mime": "1.6.0",
"ms": "2.1.3",
"on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
},
"engines": {
"node": ">= 18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
"node": ">= 0.8.0"
}
},
"node_modules/send/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/send/node_modules/debug/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/send/node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/serve-static": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz",
"integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==",
"version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"dependencies": {
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"parseurl": "^1.3.3",
"send": "^1.2.0"
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"parseurl": "~1.3.3",
"send": "0.19.0"
},
"engines": {
"node": ">= 18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
"node": ">= 0.8.0"
}
},
"node_modules/setprototypeof": {
@@ -808,7 +866,8 @@
},
"node_modules/side-channel": {
"version": "1.1.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3",
@@ -825,7 +884,8 @@
},
"node_modules/side-channel-list": {
"version": "1.0.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
"dependencies": {
"es-errors": "^1.3.0",
"object-inspect": "^1.13.3"
@@ -839,7 +899,8 @@
},
"node_modules/side-channel-map": {
"version": "1.0.1",
"license": "MIT",
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
@@ -855,7 +916,8 @@
},
"node_modules/side-channel-weakmap": {
"version": "1.0.2",
"license": "MIT",
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
"dependencies": {
"call-bound": "^1.0.2",
"es-errors": "^1.3.0",
@@ -871,9 +933,8 @@
}
},
"node_modules/statuses": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
"version": "2.0.1",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
@@ -890,13 +951,11 @@
"license": "MIT"
},
"node_modules/type-is": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
"version": "1.6.18",
"license": "MIT",
"dependencies": {
"content-type": "^1.0.5",
"media-typer": "^1.1.0",
"mime-types": "^3.0.0"
"media-typer": "0.3.0",
"mime-types": "~2.1.24"
},
"engines": {
"node": ">= 0.6"
@@ -909,6 +968,13 @@
"node": ">= 0.8"
}
},
"node_modules/utils-merge": {
"version": "1.0.1",
"license": "MIT",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/vary": {
"version": "1.1.2",
"license": "MIT",
@@ -927,11 +993,6 @@
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
}
}
}

View File

@@ -11,10 +11,9 @@
"keywords": [],
"author": "Microsoft Corporation",
"dependencies": {
"body-parser": "^2.2.2",
"express": "^5.2.1",
"follow-redirects": "^1.15.6",
"http-proxy-middleware": "^3.0.5",
"body-parser": "^1.20.3",
"express": "^4.21.2",
"http-proxy-middleware": "^3.0.3",
"node": "^20.19.5",
"node-fetch": "^2.6.1",
"path-to-regexp": "^0.1.12"

View File

@@ -1,11 +0,0 @@
import "i18next";
import Resources from "../Localization/en/Resources.json";
declare module "i18next" {
interface CustomTypeOptions {
defaultNS: "Resources";
resources: {
Resources: typeof Resources;
};
}
}

View File

@@ -1,7 +1,5 @@
import { MessageTypes } from "../Contracts/ExplorerContracts";
import { SubscriptionType } from "../Contracts/SubscriptionType";
import { isExpectedError } from "../Metrics/ErrorClassification";
import { scenarioMonitor } from "../Metrics/ScenarioMonitor";
import { userContext } from "../UserContext";
import { ARMError } from "../Utils/arm/request";
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
@@ -9,36 +7,19 @@ import { HttpStatusCodes } from "./Constants";
import { logError } from "./Logger";
import { sendMessage } from "./MessageHandler";
export interface HandleErrorOptions {
/** Optional redacted error to use for telemetry logging instead of the original error */
redactedError?: string | ARMError | Error;
}
export const handleError = (
error: string | ARMError | Error,
area: string,
consoleErrorPrefix?: string,
options?: HandleErrorOptions,
): void => {
export const handleError = (error: string | ARMError | Error, area: string, consoleErrorPrefix?: string): void => {
const errorMessage = getErrorMessage(error);
const errorCode = error instanceof ARMError ? error.code : undefined;
// logs error to data explorer console (always shows original, non-redacted message)
// logs error to data explorer console
const consoleErrorMessage = consoleErrorPrefix ? `${consoleErrorPrefix}:\n ${errorMessage}` : errorMessage;
logConsoleError(consoleErrorMessage);
// logs error to both app insight and kusto (use redacted message if provided)
const telemetryErrorMessage = options?.redactedError ? getErrorMessage(options.redactedError) : errorMessage;
logError(telemetryErrorMessage, area, errorCode);
// logs error to both app insight and kusto
logError(errorMessage, area, errorCode);
// checks for errors caused by firewall and sends them to portal to handle
sendNotificationForError(errorMessage, errorCode);
// Mark expected failures for health metrics (auth, firewall, permissions, etc.)
// This ensures timeouts with expected failures emit healthy instead of unhealthy
if (isExpectedError(error)) {
scenarioMonitor.markExpectedFailure();
}
};
export const getErrorMessage = (error: string | Error = ""): string => {

View File

@@ -38,7 +38,7 @@ export function queryIterator(databaseId: string, collection: Collection, query:
let continuationToken: string;
return {
fetchNext: () => {
return queryDocuments(databaseId, collection, false, query, continuationToken).then((response) => {
return queryDocuments(databaseId, collection, false, query).then((response) => {
continuationToken = response.continuationToken;
const headers: { [key: string]: string | number } = {};
response.headers.forEach((value, key) => {

View File

@@ -44,8 +44,7 @@ export const deleteDocuments = async (
documentIds: DocumentId[],
abortSignal: AbortSignal,
): Promise<IBulkDeleteResult[]> => {
const totalCount = documentIds.length;
const clearMessage = logConsoleProgress(`Deleting ${totalCount} ${getEntityName(true)}`);
const clearMessage = logConsoleProgress(`Deleting ${documentIds.length} ${getEntityName(true)}`);
try {
const v2Container = await client().database(collection.databaseId).container(collection.id());
@@ -84,7 +83,11 @@ export const deleteDocuments = async (
const flatAllResult = Array.prototype.concat.apply([], allResult);
return flatAllResult;
} catch (error) {
handleError(error, "DeleteDocuments", `Error while deleting ${totalCount} ${getEntityName(totalCount > 1)}`);
handleError(
error,
"DeleteDocuments",
`Error while deleting ${documentIds.length} ${getEntityName(documentIds.length > 1)}`,
);
throw error;
} finally {
clearMessage();

View File

@@ -1,171 +0,0 @@
import { redactSyntaxErrorMessage } from "./queryDocumentsPage";
/* Typical error to redact looks like this (the message property contains a JSON string with nested structure):
{
"message": "{\"code\":\"BadRequest\",\"message\":\"{\\\"errors\\\":[{\\\"severity\\\":\\\"Error\\\",\\\"location\\\":{\\\"start\\\":0,\\\"end\\\":5},\\\"code\\\":\\\"SC1001\\\",\\\"message\\\":\\\"Syntax error, incorrect syntax near 'Crazy'.\\\"}]}\\r\\nActivityId: d5424e10-51bd-46f7-9aec-7b40bed36f17, Windows/10.0.20348 cosmos-netstandard-sdk/3.18.0\"}"
}
*/
// Helper to create the nested error structure that matches what the SDK returns
const createNestedError = (
errors: Array<{ severity?: string; location?: { start: number; end: number }; code: string; message: string }>,
activityId: string = "test-activity-id",
): { message: string } => {
const innerErrorsJson = JSON.stringify({ errors });
const innerMessage = `${innerErrorsJson}\r\n${activityId}`;
const outerJson = JSON.stringify({ code: "BadRequest", message: innerMessage });
return { message: outerJson };
};
// Helper to parse the redacted result
const parseRedactedResult = (result: { message: string }) => {
const outerParsed = JSON.parse(result.message);
const [innerErrorsJson, activityIdPart] = outerParsed.message.split("\r\n");
const innerErrors = JSON.parse(innerErrorsJson);
return { outerParsed, innerErrors, activityIdPart };
};
describe("redactSyntaxErrorMessage", () => {
it("should redact SC1001 error message", () => {
const error = createNestedError(
[
{
severity: "Error",
location: { start: 0, end: 5 },
code: "SC1001",
message: "Syntax error, incorrect syntax near 'Crazy'.",
},
],
"ActivityId: d5424e10-51bd-46f7-9aec-7b40bed36f17",
);
const result = redactSyntaxErrorMessage(error) as { message: string };
const { outerParsed, innerErrors, activityIdPart } = parseRedactedResult(result);
expect(outerParsed.code).toBe("BadRequest");
expect(innerErrors.errors[0].message).toBe("__REDACTED__");
expect(activityIdPart).toContain("ActivityId: d5424e10-51bd-46f7-9aec-7b40bed36f17");
});
it("should redact SC2001 error message", () => {
const error = createNestedError(
[
{
severity: "Error",
location: { start: 0, end: 10 },
code: "SC2001",
message: "Some sensitive syntax error message.",
},
],
"ActivityId: abc123",
);
const result = redactSyntaxErrorMessage(error) as { message: string };
const { outerParsed, innerErrors, activityIdPart } = parseRedactedResult(result);
expect(outerParsed.code).toBe("BadRequest");
expect(innerErrors.errors[0].message).toBe("__REDACTED__");
expect(activityIdPart).toContain("ActivityId: abc123");
});
it("should redact multiple errors with SC1001 and SC2001 codes", () => {
const error = createNestedError(
[
{ severity: "Error", code: "SC1001", message: "First error" },
{ severity: "Error", code: "SC2001", message: "Second error" },
],
"ActivityId: xyz",
);
const result = redactSyntaxErrorMessage(error) as { message: string };
const { innerErrors } = parseRedactedResult(result);
expect(innerErrors.errors[0].message).toBe("__REDACTED__");
expect(innerErrors.errors[1].message).toBe("__REDACTED__");
});
it("should not redact errors with other codes", () => {
const error = createNestedError(
[{ severity: "Error", code: "SC9999", message: "This should not be redacted." }],
"ActivityId: test123",
);
const result = redactSyntaxErrorMessage(error);
expect(result).toBe(error); // Should return original error unchanged
});
it("should not modify non-BadRequest errors", () => {
const innerMessage = JSON.stringify({ errors: [{ code: "SC1001", message: "Should not be redacted" }] });
const error = {
message: JSON.stringify({ code: "NotFound", message: innerMessage }),
};
const result = redactSyntaxErrorMessage(error);
expect(result).toBe(error);
});
it("should handle errors without message property", () => {
const error = { code: "BadRequest" };
const result = redactSyntaxErrorMessage(error);
expect(result).toBe(error);
});
it("should handle non-object errors", () => {
const stringError = "Simple string error";
const nullError: null = null;
const undefinedError: undefined = undefined;
expect(redactSyntaxErrorMessage(stringError)).toBe(stringError);
expect(redactSyntaxErrorMessage(nullError)).toBe(nullError);
expect(redactSyntaxErrorMessage(undefinedError)).toBe(undefinedError);
});
it("should handle malformed JSON in message", () => {
const error = {
message: "not valid json",
};
const result = redactSyntaxErrorMessage(error);
expect(result).toBe(error);
});
it("should handle message without ActivityId suffix", () => {
const innerErrorsJson = JSON.stringify({
errors: [{ severity: "Error", code: "SC1001", message: "Syntax error near something." }],
});
const error = {
message: JSON.stringify({ code: "BadRequest", message: innerErrorsJson + "\r\n" }),
};
const result = redactSyntaxErrorMessage(error) as { message: string };
const { innerErrors } = parseRedactedResult(result);
expect(innerErrors.errors[0].message).toBe("__REDACTED__");
});
it("should preserve other error properties", () => {
const baseError = createNestedError([{ code: "SC1001", message: "Error" }], "ActivityId: test");
const error = {
...baseError,
statusCode: 400,
additionalInfo: "extra data",
};
const result = redactSyntaxErrorMessage(error) as {
message: string;
statusCode: number;
additionalInfo: string;
};
expect(result.statusCode).toBe(400);
expect(result.additionalInfo).toBe("extra data");
const { innerErrors } = parseRedactedResult(result);
expect(innerErrors.errors[0].message).toBe("__REDACTED__");
});
});

View File

@@ -4,51 +4,6 @@ import { getEntityName } from "../DocumentUtility";
import { handleError } from "../ErrorHandlingUtils";
import { MinimalQueryIterator, nextPage } from "../IteratorUtilities";
// Redact sensitive information from BadRequest errors with specific codes
export const redactSyntaxErrorMessage = (error: unknown): unknown => {
const codesToRedact = ["SC1001", "SC2001", "SC1010"];
try {
// Handle error objects with a message property
if (error && typeof error === "object" && "message" in error) {
const errorObj = error as { code?: string; message?: string };
if (typeof errorObj.message === "string") {
// Parse the inner JSON from the message
const innerJson = JSON.parse(errorObj.message);
if (innerJson.code === "BadRequest" && typeof innerJson.message === "string") {
const [innerErrorsJson, activityIdPart] = innerJson.message.split("\r\n");
const innerErrorsObj = JSON.parse(innerErrorsJson);
if (Array.isArray(innerErrorsObj.errors)) {
let modified = false;
innerErrorsObj.errors = innerErrorsObj.errors.map((err: { code?: string; message?: string }) => {
if (err.code && codesToRedact.includes(err.code)) {
modified = true;
return { ...err, message: "__REDACTED__" };
}
return err;
});
if (modified) {
// Reconstruct the message with the redacted content
const redactedMessage = JSON.stringify(innerErrorsObj) + `\r\n${activityIdPart}`;
const redactedError = {
...error,
message: JSON.stringify({ ...innerJson, message: redactedMessage }),
body: undefined as unknown, // Clear body to avoid sensitive data
};
return redactedError;
}
}
}
}
}
} catch {
// If parsing fails, return the original error
}
return error;
};
export const queryDocumentsPage = async (
resourceName: string,
documentsIterator: MinimalQueryIterator,
@@ -63,12 +18,7 @@ export const queryDocumentsPage = async (
logConsoleInfo(`Successfully fetched ${itemCount} ${entityName} for container ${resourceName}`);
return result;
} catch (error) {
// Redact sensitive information for telemetry while showing original in console
const redactedError = redactSyntaxErrorMessage(error);
handleError(error, "QueryDocumentsPage", `Failed to query ${entityName} for container ${resourceName}`, {
redactedError: redactedError as Error,
});
handleError(error, "QueryDocumentsPage", `Failed to query ${entityName} for container ${resourceName}`);
throw error;
} finally {
clearMessage();

View File

@@ -77,12 +77,6 @@ let configContext: Readonly<ConfigContext> = {
`^https:\\/\\/.*\\.fabric\\.microsoft\\.com$`,
`^https:\\/\\/.*\\.powerbi\\.com$`,
`^https:\\/\\/dataexplorer-preview\\.azurewebsites\\.net$`,
`^https:\\/\\/explorer\\.cosmos\\.sovcloud-api\\.fr$`,
`^https:\\/\\/portal\\.sovcloud-azure\\.fr$`,
`^https:\\/\\/explorer\\.cosmos\\.sovcloud-api\\.de$`,
`^https:\\/\\/portal\\.sovcloud-azure\\.de$`,
`^https:\\/\\/explorer\\.cosmos\\.sovcloud-api\\.sg$`,
`^https:\\/\\/portal\\.sovcloud-azure\\.sg$`,
], // Webpack injects this at build time
gitSha: process.env.GIT_SHA,
hostedExplorerURL: "https://cosmos.azure.com/",

View File

@@ -46,10 +46,6 @@ export type DataExploreMessageV3 =
params: {
updateType: "created" | "deleted" | "settings";
};
}
| {
type: FabricMessageTypes.RestoreContainer;
params: [];
};
export interface GetCosmosTokenMessageOptions {
verb: "connect" | "delete" | "get" | "head" | "options" | "patch" | "post" | "put" | "trace";

View File

@@ -275,7 +275,8 @@ export interface DataMaskingPolicy {
startPosition: number;
length: number;
}>;
excludedPaths?: string[];
excludedPaths: string[];
isPolicyEnabled: boolean;
}
export interface MaterializedView {

View File

@@ -395,14 +395,6 @@ describe("CopyJobUtils", () => {
expect(result).toBe(false);
});
it("should return false for different completion percentage", () => {
const jobs1 = [createMockJob("job1", "Running")];
const jobs2 = [{ ...createMockJob("job1", "Running"), CompletionPercentage: 75 }];
const result = CopyJobUtils.isEqual(jobs1, jobs2);
expect(result).toBe(false);
});
it("should return true for empty arrays", () => {
const result = CopyJobUtils.isEqual([], []);
expect(result).toBe(true);

View File

@@ -142,7 +142,7 @@ export function isEqual(prevJobs: CopyJobType[], newJobs: CopyJobType[]): boolea
if (!newJob) {
return false;
}
return prevJob.Status === newJob.Status && prevJob.CompletionPercentage === newJob.CompletionPercentage;
return prevJob.Status === newJob.Status;
});
}

View File

@@ -516,7 +516,7 @@ describe("CopyJobActionMenu", () => {
expect(screen.getByText("Cancel")).toBeInTheDocument();
});
it("should disable complete action when job is being updated", () => {
it("should handle complete action disabled state for online jobs", () => {
const job = createMockJob({
Status: CopyJobStatusType.InProgress,
Mode: CopyJobMigrationType.Online,
@@ -530,34 +530,8 @@ describe("CopyJobActionMenu", () => {
const completeButton = screen.getByText("Complete");
fireEvent.click(completeButton);
// Simulate dialog confirmation to trigger state update
const [, , , onOkCallback] = mockShowOkCancelModalDialog.mock.calls[0];
onOkCallback();
fireEvent.click(actionButton);
const completeButtonAfterClick = screen.getByText("Complete").closest("button");
expect(completeButtonAfterClick).toBeInTheDocument();
expect(completeButtonAfterClick).toHaveAttribute("aria-disabled", "true");
});
it("should disable complete action when any other action is being performed", () => {
const job = createMockJob({
Status: CopyJobStatusType.InProgress,
Mode: CopyJobMigrationType.Online,
});
render(<TestComponentWrapper job={job} />);
const actionButton = screen.getByRole("button", { name: "Actions" });
fireEvent.click(actionButton);
const pauseButton = screen.getByText("Pause");
fireEvent.click(pauseButton);
fireEvent.click(actionButton);
const completeButtonAfterClick = screen.getByText("Complete").closest("button");
expect(completeButtonAfterClick).toBeInTheDocument();
expect(completeButtonAfterClick).toHaveAttribute("aria-disabled", "true");
expect(screen.getByText("Complete")).toBeInTheDocument();
});
});

View File

@@ -61,6 +61,7 @@ const CopyJobActionMenu: React.FC<CopyJobActionMenuProps> = ({ job, handleClick
const getMenuItems = (): IContextualMenuProps["items"] => {
const isThisJobUpdating = updatingJobAction?.jobName === job.Name;
const updatingAction = updatingJobAction?.action;
const baseItems = [
{
@@ -104,7 +105,7 @@ const CopyJobActionMenu: React.FC<CopyJobActionMenuProps> = ({ job, handleClick
text: ContainerCopyMessages.MonitorJobs.Actions.complete,
iconProps: { iconName: "CheckMark" },
onClick: () => showActionConfirmationDialog(job, CopyJobActions.complete),
disabled: isThisJobUpdating,
disabled: isThisJobUpdating && updatingAction === CopyJobActions.complete,
});
}
return filteredItems;

View File

@@ -11,17 +11,9 @@ jest.mock("../../Actions/CopyJobActions", () => ({
jest.mock("./CopyJobColumns", () => ({
getColumns: jest.fn(() => [
{
key: "LastUpdatedTime",
name: "Date & time",
fieldName: "LastUpdatedTime",
minWidth: 140,
maxWidth: 300,
isResizable: true,
},
{
key: "Name",
name: "Job name",
name: "Name",
fieldName: "Name",
minWidth: 140,
maxWidth: 300,
@@ -173,165 +165,6 @@ describe("CopyJobsList", () => {
expect(screen.getByTestId("action-menu-job-2")).toBeInTheDocument();
expect(screen.getByTestId("action-menu-job-3")).toBeInTheDocument();
});
it("renders filter TextField with data-test attribute", () => {
render(<CopyJobsList jobs={mockJobs} handleActionClick={mockHandleActionClick} />);
const filterTextField = document.querySelector('[data-test="CopyJobsList/FilterTextField"]');
expect(filterTextField).toBeInTheDocument();
});
it("renders search TextField with correct placeholder", () => {
render(<CopyJobsList jobs={mockJobs} handleActionClick={mockHandleActionClick} />);
const searchInput = screen.getByPlaceholderText("Search jobs...");
expect(searchInput).toBeInTheDocument();
});
});
describe("Filtering", () => {
it("filters jobs by Name when text is entered", async () => {
render(<CopyJobsList jobs={mockJobs} handleActionClick={mockHandleActionClick} />);
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: "Job 1" } });
await waitFor(() => {
expect(screen.getByText("Test Job 1")).toBeInTheDocument();
expect(screen.queryByText("Test Job 2")).not.toBeInTheDocument();
expect(screen.queryByText("Test Job 3")).not.toBeInTheDocument();
});
});
it("filters jobs case-insensitively", async () => {
render(<CopyJobsList jobs={mockJobs} handleActionClick={mockHandleActionClick} />);
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: "test job 1" } });
await waitFor(() => {
expect(screen.getByText("Test Job 1")).toBeInTheDocument();
expect(screen.queryByText("Test Job 2")).not.toBeInTheDocument();
});
});
it("shows all jobs when filter text is empty", async () => {
render(<CopyJobsList jobs={mockJobs} handleActionClick={mockHandleActionClick} />);
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: "Job 1" } });
await waitFor(() => {
expect(screen.queryByText("Test Job 2")).not.toBeInTheDocument();
});
fireEvent.change(filterInput, { target: { value: "" } });
await waitFor(() => {
expect(screen.getByText("Test Job 1")).toBeInTheDocument();
expect(screen.getByText("Test Job 2")).toBeInTheDocument();
expect(screen.getByText("Test Job 3")).toBeInTheDocument();
});
});
it("filters jobs by Status across all columns", async () => {
render(<CopyJobsList jobs={mockJobs} handleActionClick={mockHandleActionClick} />);
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: CopyJobStatusType.Running } });
await waitFor(() => {
expect(screen.getByText("Test Job 1")).toBeInTheDocument();
expect(screen.queryByText("Test Job 2")).not.toBeInTheDocument();
expect(screen.queryByText("Test Job 3")).not.toBeInTheDocument();
});
});
it("filters jobs by Mode across all columns", async () => {
render(<CopyJobsList jobs={mockJobs} handleActionClick={mockHandleActionClick} />);
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: "Offline" } });
await waitFor(() => {
expect(screen.queryByText("Test Job 1")).not.toBeInTheDocument();
expect(screen.getByText("Test Job 2")).toBeInTheDocument();
expect(screen.queryByText("Test Job 3")).not.toBeInTheDocument();
});
});
it("shows no results when filter matches no jobs", async () => {
render(<CopyJobsList jobs={mockJobs} handleActionClick={mockHandleActionClick} />);
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: "NonExistentJob" } });
await waitFor(() => {
expect(screen.queryByText("Test Job 1")).not.toBeInTheDocument();
expect(screen.queryByText("Test Job 2")).not.toBeInTheDocument();
expect(screen.queryByText("Test Job 3")).not.toBeInTheDocument();
});
});
it("filters by partial text match", async () => {
render(<CopyJobsList jobs={mockJobs} handleActionClick={mockHandleActionClick} />);
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: "Test" } });
await waitFor(() => {
expect(screen.getByText("Test Job 1")).toBeInTheDocument();
expect(screen.getByText("Test Job 2")).toBeInTheDocument();
expect(screen.getByText("Test Job 3")).toBeInTheDocument();
});
});
it("resets pagination when filter changes", async () => {
const manyJobs: CopyJobType[] = Array.from({ length: 25 }, (_, i) => ({
...mockJobs[0],
ID: `job-${i + 1}`,
Name: `Test Job ${i + 1}`,
}));
render(<CopyJobsList jobs={manyJobs} handleActionClick={mockHandleActionClick} pageSize={10} />);
// Navigate to page 2
fireEvent.click(screen.getByLabelText("Go to next page"));
await waitFor(() => {
expect(screen.getByText("Showing 11 - 20 of 25 items")).toBeInTheDocument();
});
// Apply filter - should reset to page 1
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: "Job 1" } });
await waitFor(() => {
// Filtered results show from the beginning
expect(screen.getByText("Test Job 1")).toBeInTheDocument();
});
});
it("updates filtered count in pager", async () => {
const manyJobs: CopyJobType[] = Array.from({ length: 25 }, (_, i) => ({
...mockJobs[0],
ID: `job-${i + 1}`,
Name: i < 5 ? `Alpha Job ${i + 1}` : `Beta Job ${i + 1}`,
}));
render(<CopyJobsList jobs={manyJobs} handleActionClick={mockHandleActionClick} pageSize={10} />);
expect(screen.getByText("Showing 1 - 10 of 25 items")).toBeInTheDocument();
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: "Alpha" } });
await waitFor(() => {
expect(screen.queryByText("Showing 1 - 10 of 25 items")).not.toBeInTheDocument();
// Pager should not be visible since filtered results (5) are less than page size (10)
expect(screen.queryByLabelText("Go to next page")).not.toBeInTheDocument();
});
});
});
describe("Pagination", () => {
@@ -509,7 +342,7 @@ describe("CopyJobsList", () => {
describe("Component Props", () => {
it("uses default page size when not provided", () => {
const manyJobs: CopyJobType[] = Array.from({ length: 20 }, (_, i) => ({
const manyJobs: CopyJobType[] = Array.from({ length: 12 }, (_, i) => ({
...mockJobs[0],
ID: `job-${i + 1}`,
Name: `Test Job ${i + 1}`,
@@ -518,7 +351,7 @@ describe("CopyJobsList", () => {
render(<CopyJobsList jobs={manyJobs} handleActionClick={mockHandleActionClick} />);
expect(screen.getByLabelText("Go to next page")).toBeInTheDocument();
expect(screen.getByText("Showing 1 - 15 of 20 items")).toBeInTheDocument();
expect(screen.getByText("Showing 1 - 10 of 12 items")).toBeInTheDocument();
});
it("passes correct props to getColumns function", async () => {
@@ -607,33 +440,7 @@ describe("CopyJobsList", () => {
render(<CopyJobsList jobs={largeJobsList} handleActionClick={mockHandleActionClick} />);
}).not.toThrow();
expect(screen.getByText("Showing 1 - 15 of 1000 items")).toBeInTheDocument();
});
it("handles filtering with null or undefined values gracefully", async () => {
const jobsWithNullValues: CopyJobType[] = [
{
...mockJobs[0],
ID: "job-with-values",
Name: "Valid Job",
},
{
...mockJobs[1],
ID: "job-null-name",
Name: undefined as unknown as string,
},
];
expect(() => {
render(<CopyJobsList jobs={jobsWithNullValues} handleActionClick={mockHandleActionClick} />);
}).not.toThrow();
const filterInput = screen.getByPlaceholderText("Search jobs...");
fireEvent.change(filterInput, { target: { value: "Valid" } });
await waitFor(() => {
expect(screen.getByText("Valid Job")).toBeInTheDocument();
});
expect(screen.getByText("Showing 1 - 10 of 1000 items")).toBeInTheDocument();
});
});
});

View File

@@ -12,9 +12,8 @@ import {
Stack,
Sticky,
StickyPositionType,
TextField,
} from "@fluentui/react";
import React, { useEffect, useMemo } from "react";
import React, { useEffect } from "react";
import Pager from "../../../../Common/Pager";
import { useThemeStore } from "../../../../hooks/useTheme";
import { getThemeTokens } from "../../../Theme/ThemeUtil";
@@ -31,15 +30,9 @@ interface CopyJobsListProps {
const styles = {
container: { height: "100%" } as React.CSSProperties,
stackItem: { position: "relative", marginBottom: "20px" } as React.CSSProperties,
filterContainer: {
margin: "15px 5px",
},
};
const PAGE_SIZE = 15;
// Columns to search across
const searchableFields = ["Name", "Status", "LastUpdatedTime", "Mode"];
const PAGE_SIZE = 10;
const CopyJobsList: React.FC<CopyJobsListProps> = ({ jobs, handleActionClick, pageSize = PAGE_SIZE }) => {
const isDarkMode = useThemeStore((state) => state.isDarkMode);
@@ -48,23 +41,6 @@ const CopyJobsList: React.FC<CopyJobsListProps> = ({ jobs, handleActionClick, pa
const [sortedJobs, setSortedJobs] = React.useState<CopyJobType[]>(jobs);
const [sortedColumnKey, setSortedColumnKey] = React.useState<string | undefined>(undefined);
const [isSortedDescending, setIsSortedDescending] = React.useState<boolean>(false);
const [filterText, setFilterText] = React.useState<string>("");
const filteredJobs = useMemo(() => {
if (!filterText) {
return sortedJobs;
}
const lowerFilterText = filterText.toLowerCase();
return sortedJobs.filter((job: any) => {
return searchableFields.some((field) => {
const value = job[field];
if (value === undefined || value === null) {
return false;
}
return String(value).toLowerCase().includes(lowerFilterText);
});
});
}, [sortedJobs, filterText]);
useEffect(() => {
setSortedJobs(jobs);
@@ -88,15 +64,7 @@ const CopyJobsList: React.FC<CopyJobsListProps> = ({ jobs, handleActionClick, pa
setStartIndex(0);
};
const sortableColumns: IColumn[] = getColumns(handleSort, handleActionClick, sortedColumnKey, isSortedDescending);
const handleFilterTextChange = (
_event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
newValue?: string,
) => {
setFilterText(newValue || "");
setStartIndex(0);
};
const columns: IColumn[] = getColumns(handleSort, handleActionClick, sortedColumnKey, isSortedDescending);
const _handleRowClick = (job: CopyJobType) => {
openCopyJobDetailsPanel(job);
@@ -113,25 +81,14 @@ const CopyJobsList: React.FC<CopyJobsListProps> = ({ jobs, handleActionClick, pa
return (
<div style={styles.container}>
<Stack verticalFill={true}>
<Stack.Item>
<div style={styles.filterContainer}>
<TextField
data-test="CopyJobsList/FilterTextField"
placeholder="Search jobs..."
ariaLabel="Search jobs"
value={filterText}
onChange={handleFilterTextChange}
/>
</div>
</Stack.Item>
<Stack.Item verticalFill={true} grow={1} shrink={1} style={styles.stackItem}>
<ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto}>
<ShimmeredDetailsList
className="CopyJobListContainer"
onRenderRow={_onRenderRow}
checkboxVisibility={2}
columns={sortableColumns}
items={filteredJobs.slice(startIndex, startIndex + pageSize)}
columns={columns}
items={sortedJobs.slice(startIndex, startIndex + pageSize)}
enableShimmer={false}
constrainMode={ConstrainMode.unconstrained}
layoutMode={DetailsListLayoutMode.justified}
@@ -160,12 +117,12 @@ const CopyJobsList: React.FC<CopyJobsListProps> = ({ jobs, handleActionClick, pa
/>
</ScrollablePane>
</Stack.Item>
{filteredJobs.length > pageSize && (
{sortedJobs.length > pageSize && (
<Stack.Item>
<Pager
disabled={false}
startIndex={startIndex}
totalCount={filteredJobs.length}
totalCount={sortedJobs.length}
pageSize={pageSize}
onLoadPage={(startIdx /* pageSize */) => {
setStartIndex(startIdx);

View File

@@ -1,27 +1,5 @@
@import "../../../less/Common/Constants.less";
.themedTextFieldStyles() {
.ms-TextField {
.ms-TextField-fieldGroup {
background-color: var(--colorNeutralBackground1);
border-color: var(--colorNeutralStroke1);
}
.ms-TextField-field {
color: var(--colorNeutralForeground1);
background-color: var(--colorNeutralBackground1);
&::placeholder {
color: var(--colorNeutralForeground4);
}
}
.ms-Label {
color: var(--colorNeutralForeground1);
}
}
}
// Common theme-aware classes
.themeText {
color: var(--colorNeutralForeground1);
@@ -141,8 +119,25 @@
filter: invert(1);
}
.themedTextFieldStyles();
.ms-TextField {
.ms-TextField-fieldGroup {
background-color: var(--colorNeutralBackground1);
border-color: var(--colorNeutralStroke1);
}
.ms-TextField-field {
color: var(--colorNeutralForeground1);
background-color: var(--colorNeutralBackground1);
&::placeholder {
color: var(--colorNeutralForeground4);
}
}
.ms-Label {
color: var(--colorNeutralForeground1);
}
}
.migrationTypeDescription {
p {
color: var(--colorNeutralForeground1);
@@ -178,11 +173,6 @@
width: 100%;
max-width: 100%;
margin: 0 auto;
body.isDarkMode & {
.themedTextFieldStyles();
}
.ms-DetailsList {
width: 100%;

View File

@@ -7,9 +7,7 @@ import {
AddGlobalSecondaryIndexPanelProps,
} from "Explorer/Panes/AddGlobalSecondaryIndexPanel/AddGlobalSecondaryIndexPanel";
import { useDatabases } from "Explorer/useDatabases";
import { Keys } from "Localization/Keys.generated";
import { t } from "Localization/t";
import { isFabric, isFabricNative, openRestoreContainerDialog } from "Platform/Fabric/FabricUtil";
import { isFabric, isFabricNative } from "Platform/Fabric/FabricUtil";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
import { ReactTabKind, useTabs } from "hooks/useTabs";
@@ -26,7 +24,6 @@ import DeleteTriggerIcon from "../../images/DeleteTrigger.svg";
import DeleteUDFIcon from "../../images/DeleteUDF.svg";
import HostedTerminalIcon from "../../images/Hosted-Terminal.svg";
import * as ViewModels from "../Contracts/ViewModels";
import { extractFeatures } from "../Platform/Hosted/extractFeatures";
import { userContext } from "../UserContext";
import { getCollectionName, getDatabaseName } from "../Utils/APITypeUtils";
import { useSidePanel } from "../hooks/useSidePanel";
@@ -59,21 +56,10 @@ export const createDatabaseContextMenu = (container: Explorer, databaseId: strin
{
iconSrc: AddCollectionIcon,
onClick: () => container.onNewCollectionClicked({ databaseId }),
label: t(Keys.contextMenu.newContainer, { containerName: getCollectionName() }),
label: `New ${getCollectionName()}`,
},
];
if (isFabricNative() && !userContext.fabricContext?.isReadOnly) {
const features = extractFeatures();
if (features?.enableRestoreContainer) {
items.push({
iconSrc: AddCollectionIcon,
onClick: () => openRestoreContainerDialog(),
label: t(Keys.contextMenu.restoreContainer, { containerName: getCollectionName() }),
});
}
}
if (!isFabricNative() && (userContext.apiType !== "Tables" || userContext.features.enableSDKoperations)) {
items.push({
iconSrc: DeleteDatabaseIcon,
@@ -82,11 +68,11 @@ export const createDatabaseContextMenu = (container: Explorer, databaseId: strin
useSidePanel
.getState()
.openSidePanel(
t(Keys.contextMenu.deleteDatabase, { databaseName: getDatabaseName() }),
"Delete " + getDatabaseName(),
<DeleteDatabaseConfirmationPanel refreshDatabases={() => container.refreshAllDatabases()} />,
);
},
label: t(Keys.contextMenu.deleteDatabase, { databaseName: getDatabaseName() }),
label: `Delete ${getDatabaseName()}`,
styleClass: "deleteDatabaseMenuItem",
});
}
@@ -102,7 +88,7 @@ export const createCollectionContextMenuButton = (
items.push({
iconSrc: AddSqlQueryIcon,
onClick: () => selectedCollection && selectedCollection.onNewQueryClick(selectedCollection, undefined),
label: t(Keys.contextMenu.newSqlQuery),
label: "New SQL Query",
});
}
@@ -110,7 +96,7 @@ export const createCollectionContextMenuButton = (
items.push({
iconSrc: AddSqlQueryIcon,
onClick: () => selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, undefined),
label: t(Keys.contextMenu.newQuery),
label: "New Query",
});
items.push({
@@ -125,8 +111,8 @@ export const createCollectionContextMenuButton = (
},
label:
useNotebook.getState().isShellEnabled || userContext.features.enableCloudShell
? t(Keys.contextMenu.openMongoShell)
: t(Keys.contextMenu.newShell),
? "Open Mongo Shell"
: "New Shell",
});
}
@@ -139,7 +125,7 @@ export const createCollectionContextMenuButton = (
onClick: () => {
container.openNotebookTerminal(ViewModels.TerminalKind.Cassandra);
},
label: t(Keys.contextMenu.openCassandraShell),
label: "Open Cassandra Shell",
});
}
@@ -152,7 +138,7 @@ export const createCollectionContextMenuButton = (
onClick: () => {
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, undefined);
},
label: t(Keys.contextMenu.newStoredProcedure),
label: "New Stored Procedure",
});
items.push({
@@ -160,7 +146,7 @@ export const createCollectionContextMenuButton = (
onClick: () => {
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection);
},
label: t(Keys.contextMenu.newUdf),
label: "New UDF",
});
items.push({
@@ -168,7 +154,7 @@ export const createCollectionContextMenuButton = (
onClick: () => {
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection, undefined);
},
label: t(Keys.contextMenu.newTrigger),
label: "New Trigger",
});
}
@@ -181,11 +167,11 @@ export const createCollectionContextMenuButton = (
useSidePanel
.getState()
.openSidePanel(
t(Keys.contextMenu.deleteContainer, { containerName: getCollectionName() }),
"Delete " + getCollectionName(),
<DeleteCollectionConfirmationPane refreshDatabases={() => container.refreshAllDatabases()} />,
);
},
label: t(Keys.contextMenu.deleteContainer, { containerName: getCollectionName() }),
label: `Delete ${getCollectionName()}`,
styleClass: "deleteCollectionMenuItem",
});
}
@@ -222,14 +208,14 @@ export const createSampleCollectionContextMenuButton = (): TreeNodeMenuItem[] =>
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
traceOpen(Action.OpenQueryCopilotFromNewQuery, { apiType: userContext.apiType });
},
label: t(Keys.contextMenu.newSqlQuery),
label: "New SQL Query",
});
} else if (copilotVersion === "v2.0") {
const sampleCollection = useDatabases.getState().sampleDataResourceTokenCollection;
items.push({
iconSrc: AddSqlQueryIcon,
onClick: () => sampleCollection && sampleCollection.onNewQueryClick(sampleCollection, undefined),
label: t(Keys.contextMenu.newSqlQuery),
label: "New SQL Query",
});
}
}
@@ -249,7 +235,7 @@ export const createStoreProcedureContextMenuItems = (
{
iconSrc: DeleteSprocIcon,
onClick: () => storedProcedure.delete(),
label: t(Keys.contextMenu.deleteStoredProcedure),
label: "Delete Stored Procedure",
},
];
};
@@ -263,7 +249,7 @@ export const createTriggerContextMenuItems = (container: Explorer, trigger: Trig
{
iconSrc: DeleteTriggerIcon,
onClick: () => trigger.delete(),
label: t(Keys.contextMenu.deleteTrigger),
label: "Delete Trigger",
},
];
};
@@ -280,7 +266,7 @@ export const createUserDefinedFunctionContextMenuItems = (
{
iconSrc: DeleteUDFIcon,
onClick: () => userDefinedFunction.delete(),
label: t(Keys.contextMenu.deleteUdf),
label: "Delete User Defined Function",
},
];
};

View File

@@ -30,6 +30,7 @@ jest.mock("../../../Common/dataAccess/updateCollection", () => ({
dataMaskingPolicy: {
includedPaths: [],
excludedPaths: ["/excludedPath"],
isPolicyEnabled: true,
},
indexes: [],
}),
@@ -306,10 +307,12 @@ describe("SettingsComponent", () => {
dataMaskingContent: {
includedPaths: [],
excludedPaths: ["/excludedPath"],
isPolicyEnabled: true,
},
dataMaskingContentBaseline: {
includedPaths: [],
excludedPaths: [],
isPolicyEnabled: false,
},
isDataMaskingDirty: true,
});
@@ -323,6 +326,7 @@ describe("SettingsComponent", () => {
expect(wrapper.state("dataMaskingContentBaseline")).toEqual({
includedPaths: [],
excludedPaths: ["/excludedPath"],
isPolicyEnabled: true,
});
});
@@ -336,6 +340,7 @@ describe("SettingsComponent", () => {
const invalidPolicy: InvalidPolicy = {
includedPaths: "invalid",
excludedPaths: [],
isPolicyEnabled: false,
};
// Use type assertion since we're deliberately testing with invalid data
settingsComponentInstance["onDataMaskingContentChange"](invalidPolicy as unknown as DataModels.DataMaskingPolicy);
@@ -344,6 +349,7 @@ describe("SettingsComponent", () => {
expect(wrapper.state("dataMaskingContent")).toEqual({
includedPaths: "invalid",
excludedPaths: [],
isPolicyEnabled: false,
});
expect(wrapper.state("dataMaskingValidationErrors")).toEqual(["includedPaths must be an array"]);
@@ -358,6 +364,7 @@ describe("SettingsComponent", () => {
},
],
excludedPaths: ["/excludedPath"],
isPolicyEnabled: true,
};
settingsComponentInstance["onDataMaskingContentChange"](validPolicy);
@@ -381,6 +388,7 @@ describe("SettingsComponent", () => {
},
],
excludedPaths: ["/excludedPath1"],
isPolicyEnabled: false,
};
const modifiedPolicy = {
@@ -393,6 +401,7 @@ describe("SettingsComponent", () => {
},
],
excludedPaths: ["/excludedPath2"],
isPolicyEnabled: true,
};
// Set initial state

View File

@@ -16,7 +16,7 @@ import {
import { useIndexingPolicyStore } from "Explorer/Tabs/QueryTab/ResultsView";
import { useDatabases } from "Explorer/useDatabases";
import { isFabricNative } from "Platform/Fabric/FabricUtil";
import { isVectorSearchEnabled } from "Utils/CapabilityUtils";
import { isCapabilityEnabled, isVectorSearchEnabled } from "Utils/CapabilityUtils";
import { isRunningOnPublicCloud } from "Utils/CloudUtils";
import * as React from "react";
import DiscardIcon from "../../../../images/discard.svg";
@@ -70,7 +70,6 @@ import {
getMongoNotification,
getTabTitle,
hasDatabaseSharedThroughput,
isDataMaskingEnabled,
isDirty,
parseConflictResolutionMode,
parseConflictResolutionProcedure,
@@ -687,14 +686,22 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
this.setState({ isComputedPropertiesDirty: isComputedPropertiesDirty });
private onDataMaskingContentChange = (newDataMasking: DataModels.DataMaskingPolicy): void => {
if (!newDataMasking.excludedPaths) {
newDataMasking.excludedPaths = [];
}
if (!newDataMasking.includedPaths) {
newDataMasking.includedPaths = [];
}
const validationErrors = [];
if (newDataMasking.includedPaths === undefined || newDataMasking.includedPaths === null) {
validationErrors.push("includedPaths is required");
} else if (!Array.isArray(newDataMasking.includedPaths)) {
if (!Array.isArray(newDataMasking.includedPaths)) {
validationErrors.push("includedPaths must be an array");
}
if (newDataMasking.excludedPaths !== undefined && !Array.isArray(newDataMasking.excludedPaths)) {
validationErrors.push("excludedPaths must be an array if provided");
if (!Array.isArray(newDataMasking.excludedPaths)) {
validationErrors.push("excludedPaths must be an array");
}
if (typeof newDataMasking.isPolicyEnabled !== "boolean") {
validationErrors.push("isPolicyEnabled must be a boolean");
}
this.setState({
@@ -835,6 +842,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
const dataMaskingContent: DataModels.DataMaskingPolicy = {
includedPaths: this.collection.dataMaskingPolicy?.()?.includedPaths || [],
excludedPaths: this.collection.dataMaskingPolicy?.()?.excludedPaths || [],
isPolicyEnabled: this.collection.dataMaskingPolicy?.()?.isPolicyEnabled ?? true,
};
const conflictResolutionPolicy: DataModels.ConflictResolutionPolicy =
this.collection.conflictResolutionPolicy && this.collection.conflictResolutionPolicy();
@@ -1065,8 +1073,8 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
newCollection.fullTextPolicy = this.state.fullTextPolicy;
// Only send data masking policy if it was modified (dirty) and data masking is enabled
if (this.state.isDataMaskingDirty && isDataMaskingEnabled(this.collection.dataMaskingPolicy?.())) {
// Only send data masking policy if it was modified (dirty)
if (this.state.isDataMaskingDirty && isCapabilityEnabled(Constants.CapabilityNames.EnableDynamicDataMasking)) {
newCollection.dataMaskingPolicy = this.state.dataMaskingContent;
}
@@ -1455,7 +1463,15 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
});
}
if (isDataMaskingEnabled(this.collection.dataMaskingPolicy?.())) {
// Check if DDM should be enabled
const shouldEnableDDM = (): boolean => {
const hasDataMaskingCapability = isCapabilityEnabled(Constants.CapabilityNames.EnableDynamicDataMasking);
const isSqlAccount = userContext.apiType === "SQL";
return isSqlAccount && hasDataMaskingCapability; // Only show for SQL accounts with DDM capability
};
if (shouldEnableDDM()) {
const dataMaskingComponentProps: DataMaskingComponentProps = {
shouldDiscardDataMasking: this.state.shouldDiscardDataMasking,
resetShouldDiscardDataMasking: this.resetShouldDiscardDataMasking,

View File

@@ -53,6 +53,7 @@ describe("DataMaskingComponent", () => {
},
],
excludedPaths: [],
isPolicyEnabled: false,
};
let changeContentCallback: () => void;
@@ -77,7 +78,7 @@ describe("DataMaskingComponent", () => {
<DataMaskingComponent
{...mockProps}
dataMaskingContent={samplePolicy}
dataMaskingContentBaseline={{ ...samplePolicy, excludedPaths: ["/excluded"] }}
dataMaskingContentBaseline={{ ...samplePolicy, isPolicyEnabled: true }}
/>,
);
@@ -122,7 +123,7 @@ describe("DataMaskingComponent", () => {
});
it("resets content when shouldDiscardDataMasking is true", async () => {
const baselinePolicy = { ...samplePolicy, excludedPaths: ["/excluded"] };
const baselinePolicy = { ...samplePolicy, isPolicyEnabled: true };
const wrapper = mount(
<DataMaskingComponent
@@ -158,7 +159,7 @@ describe("DataMaskingComponent", () => {
wrapper.update();
// Update baseline to trigger componentDidUpdate
const newBaseline = { ...samplePolicy, excludedPaths: ["/excluded"] };
const newBaseline = { ...samplePolicy, isPolicyEnabled: true };
wrapper.setProps({ dataMaskingContentBaseline: newBaseline });
expect(mockProps.onDataMaskingDirtyChange).toHaveBeenCalledWith(true);
@@ -173,6 +174,7 @@ describe("DataMaskingComponent", () => {
const invalidPolicy: Record<string, unknown> = {
includedPaths: "not an array",
excludedPaths: [] as string[],
isPolicyEnabled: "not a boolean",
};
mockGetValue.mockReturnValue(JSON.stringify(invalidPolicy));
@@ -195,7 +197,7 @@ describe("DataMaskingComponent", () => {
wrapper.update();
// First change
const modifiedPolicy1 = { ...samplePolicy, excludedPaths: ["/path1"] };
const modifiedPolicy1 = { ...samplePolicy, isPolicyEnabled: true };
mockGetValue.mockReturnValue(JSON.stringify(modifiedPolicy1));
changeContentCallback();
expect(mockProps.onDataMaskingDirtyChange).toHaveBeenCalledWith(true);

View File

@@ -1,10 +1,12 @@
import { MessageBar, MessageBarType, Stack } from "@fluentui/react";
import * as monaco from "monaco-editor";
import * as React from "react";
import * as Constants from "../../../../Common/Constants";
import * as DataModels from "../../../../Contracts/DataModels";
import { isCapabilityEnabled } from "../../../../Utils/CapabilityUtils";
import { loadMonaco } from "../../../LazyMonaco";
import { titleAndInputStackProps, unsavedEditorWarningMessage } from "../SettingsRenderUtils";
import { isDirty as isContentDirty, isDataMaskingEnabled } from "../SettingsUtils";
import { isDirty as isContentDirty } from "../SettingsUtils";
export interface DataMaskingComponentProps {
shouldDiscardDataMasking: boolean;
@@ -22,8 +24,16 @@ interface DataMaskingComponentState {
}
const emptyDataMaskingPolicy: DataModels.DataMaskingPolicy = {
includedPaths: [],
includedPaths: [
{
path: "/",
strategy: "Default",
startPosition: 0,
length: -1,
},
],
excludedPaths: [],
isPolicyEnabled: true,
};
export class DataMaskingComponent extends React.Component<DataMaskingComponentProps, DataMaskingComponentState> {
@@ -130,7 +140,7 @@ export class DataMaskingComponent extends React.Component<DataMaskingComponentPr
};
public render(): JSX.Element {
if (!isDataMaskingEnabled(this.props.dataMaskingContent)) {
if (!isCapabilityEnabled(Constants.CapabilityNames.EnableDynamicDataMasking)) {
return null;
}

View File

@@ -2,8 +2,6 @@ import * as Constants from "../../../Common/Constants";
import * as DataModels from "../../../Contracts/DataModels";
import * as ViewModels from "../../../Contracts/ViewModels";
import { isFabricNative } from "../../../Platform/Fabric/FabricUtil";
import { userContext } from "../../../UserContext";
import { isCapabilityEnabled } from "../../../Utils/CapabilityUtils";
import { MongoIndex } from "../../../Utils/arm/generatedClients/cosmos/types";
const zeroValue = 0;
@@ -90,19 +88,6 @@ export const hasDatabaseSharedThroughput = (collection: ViewModels.Collection):
return database?.isDatabaseShared() && !collection.offer();
};
export const isDataMaskingEnabled = (dataMaskingPolicy?: DataModels.DataMaskingPolicy): boolean => {
const isSqlAccount = userContext.apiType === "SQL";
if (!isSqlAccount) {
return false;
}
const hasDataMaskingCapability = isCapabilityEnabled(Constants.CapabilityNames.EnableDynamicDataMasking);
const hasDataMaskingPolicyFromCollection =
dataMaskingPolicy?.includedPaths?.length > 0 || dataMaskingPolicy?.excludedPaths?.length > 0;
return hasDataMaskingCapability || hasDataMaskingPolicyFromCollection;
};
export const parseConflictResolutionMode = (modeFromBackend: string): DataModels.ConflictResolutionMode => {
// Backend can contain different casing as it does case-insensitive comparisson
if (!modeFromBackend) {

View File

@@ -68,6 +68,7 @@ export const collection = {
dataMaskingPolicy: ko.observable<DataModels.DataMaskingPolicy>({
includedPaths: [],
excludedPaths: ["/excludedPath"],
isPolicyEnabled: true,
}),
readSettings: () => {
return;

View File

@@ -604,58 +604,6 @@ exports[`SettingsComponent renders 1`] = `
/>
</Stack>
</PivotItem>
<PivotItem
headerButtonProps={
{
"data-test": "settings-tab-header/DataMaskingTab",
}
}
headerText="Masking Policy (preview)"
itemKey="DataMaskingTab"
key="DataMaskingTab"
style={
{
"backgroundColor": "var(--colorNeutralBackground1)",
"color": "var(--colorNeutralForeground1)",
"marginTop": 20,
}
}
>
<Stack
styles={
{
"root": {
"backgroundColor": "var(--colorNeutralBackground1)",
"color": "var(--colorNeutralForeground1)",
},
}
}
>
<DataMaskingComponent
dataMaskingContent={
{
"excludedPaths": [
"/excludedPath",
],
"includedPaths": [],
}
}
dataMaskingContentBaseline={
{
"excludedPaths": [
"/excludedPath",
],
"includedPaths": [],
}
}
onDataMaskingContentChange={[Function]}
onDataMaskingDirtyChange={[Function]}
resetShouldDiscardDataMasking={[Function]}
shouldDiscardDataMasking={false}
validationErrors={[]}
/>
</Stack>
</PivotItem>
<PivotItem
headerButtonProps={
{

View File

@@ -113,7 +113,7 @@ export class ContainerSampleGenerator {
? await createMongoDocument(collection.databaseId, collection, shardKey, doc)
: await createDocument(collection, doc);
} catch (error) {
NotificationConsoleUtils.logConsoleError(error instanceof Error ? error.message : String(error));
NotificationConsoleUtils.logConsoleError(error);
}
}),
);

View File

@@ -329,10 +329,7 @@ export class NotificationConsoleComponent extends React.Component<
}
private static extractHeaderStatus(consoleData: ConsoleData) {
if (!consoleData?.message || typeof consoleData.message !== "string") {
return undefined;
}
return consoleData.message.split(":\n")[0];
return consoleData?.message.split(":\n")[0];
}
private onConsoleWasExpanded = (): void => {

View File

@@ -6,8 +6,6 @@ import { DocumentAddRegular, LinkMultipleRegular, OpenRegular } from "@fluentui/
import { SampleDataConfiguration, SampleDataImportDialog } from "Explorer/SplashScreen/SampleDataImportDialog";
import { SampleDataFile } from "Explorer/SplashScreen/SampleUtil";
import { CosmosFluentProvider } from "Explorer/Theme/ThemeUtil";
import { Keys } from "Localization/Keys.generated";
import { t } from "Localization/t";
import { isFabricNative, isFabricNativeReadOnly } from "Platform/Fabric/FabricUtil";
import * as React from "react";
import { userContext } from "UserContext";
@@ -161,8 +159,8 @@ export const FabricHomeScreen: React.FC<SplashScreenProps> = (props: SplashScree
const getSplashScreenButtons = (): JSX.Element => {
const buttons: FabricHomeScreenButtonProps[] = [
{
title: t(Keys.splashScreen.fabric.newContainer.title),
description: t(Keys.splashScreen.fabric.newContainer.description),
title: "New container",
description: "Create a destination container to store your data",
icon: <DocumentAddRegular />,
onClick: () => {
const databaseId = isFabricNative() ? userContext.fabricContext?.databaseName : undefined;
@@ -170,8 +168,8 @@ export const FabricHomeScreen: React.FC<SplashScreenProps> = (props: SplashScree
},
},
{
title: t(Keys.splashScreen.fabric.sampleData.title),
description: t(Keys.splashScreen.fabric.sampleData.description),
title: "Sample Data",
description: "Load sample data in your database",
icon: <img src={CosmosDbBlackIcon} alt={"Azure Cosmos DB icon"} aria-hidden="true" />,
onClick: () => {
setSelectedSampleDataConfiguration({
@@ -183,8 +181,8 @@ export const FabricHomeScreen: React.FC<SplashScreenProps> = (props: SplashScree
},
},
{
title: t(Keys.splashScreen.fabric.sampleVectorData.title),
description: t(Keys.splashScreen.fabric.sampleVectorData.description),
title: "Sample Vector Data",
description: "Load sample vector data with text-embedding-ada-002",
icon: <img src={AzureOpenAiIcon} alt={"Azure Open AI icon"} aria-hidden="true" />,
onClick: () => {
setSelectedSampleDataConfiguration({
@@ -196,14 +194,14 @@ export const FabricHomeScreen: React.FC<SplashScreenProps> = (props: SplashScree
},
},
{
title: t(Keys.splashScreen.fabric.appDevelopment.title),
description: t(Keys.splashScreen.fabric.appDevelopment.description),
title: "App development",
description: "Start here to use an SDK to build your apps",
icon: <LinkMultipleRegular />,
onClick: () => window.open("https://aka.ms/cosmosdbfabricsdk", "_blank"),
},
{
title: t(Keys.splashScreen.fabric.sampleGallery.title),
description: t(Keys.splashScreen.fabric.sampleGallery.description),
title: "Sample Gallery",
description: "Get real-world end-to-end samples",
icon: <img src={GithubIcon} alt={"GitHub icon"} aria-hidden="true" />,
onClick: () => window.open("https://aka.ms/CosmosFabricSamplesGallery", "_blank"),
},
@@ -224,9 +222,7 @@ export const FabricHomeScreen: React.FC<SplashScreenProps> = (props: SplashScree
);
};
const title = isFabricNativeReadOnly()
? t(Keys.splashScreen.fabric.useTitle)
: t(Keys.splashScreen.fabric.buildTitle);
const title = isFabricNativeReadOnly() ? "Use your database" : "Build your database";
return (
<>
<CosmosFluentProvider className={styles.homeContainer}>
@@ -242,9 +238,9 @@ export const FabricHomeScreen: React.FC<SplashScreenProps> = (props: SplashScree
{getSplashScreenButtons()}
{
<div className={styles.footer}>
{t(Keys.splashScreen.sections.needHelp)}{" "}
Need help?{" "}
<Link href="https://learn.microsoft.com/fabric/database/cosmos-db/overview" target="_blank">
{t(Keys.common.learnMore)} <OpenRegular />
Learn more <OpenRegular />
</Link>
</div>
}

View File

@@ -12,8 +12,6 @@ import {
} from "@fluentui/react-components";
import Explorer from "Explorer/Explorer";
import { checkContainerExists, createContainer, importData, SampleDataFile } from "Explorer/SplashScreen/SampleUtil";
import { Keys } from "Localization/Keys.generated";
import { t } from "Localization/t";
import React, { useEffect, useState } from "react";
import * as ViewModels from "../../Contracts/ViewModels";
@@ -61,7 +59,7 @@ export const SampleDataImportDialog: React.FC<{
setStatus("creating");
const databaseName = props.sampleDataConfiguration.databaseName;
if (checkContainerExists(databaseName, containerName)) {
const msg = t(Keys.splashScreen.sampleDataDialog.errorContainerExists, { containerName, databaseName });
const msg = `The container "${containerName}" in database "${databaseName}" already exists. Please delete it and retry.`;
setStatus("error");
setErrorMessage(msg);
return;
@@ -77,11 +75,7 @@ export const SampleDataImportDialog: React.FC<{
);
} catch (error) {
setStatus("error");
setErrorMessage(
t(Keys.splashScreen.sampleDataDialog.errorCreateContainer, {
error: error instanceof Error ? error.message : String(error),
}),
);
setErrorMessage(`Failed to create container: ${error instanceof Error ? error.message : String(error)}`);
return;
}
@@ -92,11 +86,7 @@ export const SampleDataImportDialog: React.FC<{
setStatus("completed");
} catch (error) {
setStatus("error");
setErrorMessage(
t(Keys.splashScreen.sampleDataDialog.errorImportData, {
error: error instanceof Error ? error.message : String(error),
}),
);
setErrorMessage(`Failed to import data: ${error instanceof Error ? error.message : String(error)}`);
}
};
@@ -122,26 +112,14 @@ export const SampleDataImportDialog: React.FC<{
const renderContent = () => {
switch (status) {
case "idle":
return t(Keys.splashScreen.sampleDataDialog.createPrompt, { containerName });
return `Create a container "${containerName}" and import sample data into it. This may take a few minutes.`;
case "creating":
return (
<Spinner
size="small"
labelPosition="above"
label={t(Keys.splashScreen.sampleDataDialog.creatingContainer, { containerName })}
/>
);
return <Spinner size="small" labelPosition="above" label={`Creating container "${containerName}"...`} />;
case "importing":
return (
<Spinner
size="small"
labelPosition="above"
label={t(Keys.splashScreen.sampleDataDialog.importingData, { containerName })}
/>
);
return <Spinner size="small" labelPosition="above" label={`Importing data into "${containerName}"...`} />;
case "completed":
return t(Keys.splashScreen.sampleDataDialog.success, { containerName });
return `Successfully created "${containerName}" with sample data.`;
case "error":
return (
<div style={{ color: "red" }}>
@@ -154,14 +132,14 @@ export const SampleDataImportDialog: React.FC<{
const getButtonLabel = () => {
switch (status) {
case "idle":
return t(Keys.splashScreen.sampleDataDialog.startButton);
return "Start";
case "creating":
case "importing":
return t(Keys.common.close);
return "Close";
case "completed":
return t(Keys.common.close);
return "Close";
case "error":
return t(Keys.common.close);
return "Close";
}
};
@@ -169,7 +147,7 @@ export const SampleDataImportDialog: React.FC<{
<Dialog open={props.open} onOpenChange={(event, data) => props.setOpen(data.open)}>
<DialogSurface>
<DialogBody>
<DialogTitle>{t(Keys.splashScreen.sampleDataDialog.title)}</DialogTitle>
<DialogTitle>Sample Data</DialogTitle>
<DialogContent>
<div className={styles.dialogContent}>{renderContent()}</div>
</DialogContent>

View File

@@ -54,6 +54,6 @@
.mainButtonsContainer {
display: flex;
gap: 0 16px;
margin: 40px auto
margin-bottom: 10px
}

View File

@@ -16,8 +16,6 @@ import { sendMessage } from "Common/MessageHandler";
import { MessageTypes } from "Contracts/ExplorerContracts";
import { TerminalKind } from "Contracts/ViewModels";
import { SplashScreenButton } from "Explorer/SplashScreen/SplashScreenButton";
import { Keys } from "Localization/Keys.generated";
import { t } from "Localization/t";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
import { useCarousel } from "hooks/useCarousel";
@@ -171,16 +169,16 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
switch (userContext.apiType) {
case "Postgres":
title = t(Keys.splashScreen.title.postgres);
subtitle = t(Keys.splashScreen.subtitle.getStarted);
title = "Welcome to Azure Cosmos DB for PostgreSQL";
subtitle = "Get started with our sample datasets, documentation, and additional tools.";
break;
case "VCoreMongo":
title = t(Keys.splashScreen.title.vcoreMongo);
subtitle = t(Keys.splashScreen.subtitle.getStarted);
title = "Welcome to Azure DocumentDB (with MongoDB compatibility)";
subtitle = "Get started with our sample datasets, documentation, and additional tools.";
break;
default:
title = t(Keys.splashScreen.title.default);
subtitle = t(Keys.splashScreen.subtitle.default);
title = "Welcome to Azure Cosmos DB";
subtitle = "Globally distributed, multi-model database service for any scale";
}
React.useEffect(() => {
@@ -251,8 +249,8 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
<Stack className="splashStackRow" horizontal>
<SplashScreenButton
imgSrc={QuickStartIcon}
title={t(Keys.splashScreen.quickStart.title)}
description={t(Keys.splashScreen.quickStart.description)}
title={"Launch quick start"}
description={"Launch a quick start tutorial to get started with sample data"}
onClick={() => {
container.onNewCollectionClicked({ isQuickstart: true });
traceOpen(Action.LaunchQuickstart, { apiType: userContext.apiType });
@@ -260,8 +258,8 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
/>
<SplashScreenButton
imgSrc={ContainersIcon}
title={t(Keys.splashScreen.newCollection.title, { collectionName: getCollectionName() })}
description={t(Keys.splashScreen.newCollection.description)}
title={`New ${getCollectionName()}`}
description={"Create a new container for storage and throughput"}
onClick={() => {
container.onNewCollectionClicked();
traceOpen(Action.NewContainerHomepage, { apiType: userContext.apiType });
@@ -272,8 +270,10 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
<SplashScreenButton
imgSrc={CosmosDBIcon}
imgSize={35}
title={t(Keys.splashScreen.samplesGallery.title)}
description={t(Keys.splashScreen.samplesGallery.description)}
title={"Azure Cosmos DB Samples Gallery"}
description={
"Discover samples that showcase scalable, intelligent app patterns. Try one now to see how fast you can go from concept to code with Cosmos DB"
}
onClick={() => {
window.open("https://azurecosmosdb.github.io/gallery/?tags=example", "_blank");
traceOpen(Action.LearningResourcesClicked, { apiType: userContext.apiType });
@@ -281,8 +281,8 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
/>
<SplashScreenButton
imgSrc={ConnectIcon}
title={t(Keys.splashScreen.connectCard.title)}
description={t(Keys.splashScreen.connectCard.description)}
title={"Connect"}
description={"Prefer using your own choice of tooling? Find the connection string you need to connect"}
onClick={() => useTabs.getState().openAndActivateReactTab(ReactTabKind.Connect)}
/>
</Stack>
@@ -297,7 +297,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
usePostgres.getState().showPostgreTeachingBubble &&
!usePostgres.getState().showResetPasswordBubble && (
<TeachingBubble
headline={t(Keys.splashScreen.teachingBubble.newToPostgres.headline)}
headline="New to Cosmos DB PGSQL?"
target={"#mainButton-quickstartDescription"}
hasCloseButton
onDismiss={() => usePostgres.getState().setShowPostgreTeachingBubble(false)}
@@ -309,14 +309,15 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
preventDismissOnScroll: true,
}}
primaryButtonProps={{
text: t(Keys.common.getStarted),
text: "Get started",
onClick: () => {
useTabs.getState().openAndActivateReactTab(ReactTabKind.Quickstart);
usePostgres.getState().setShowPostgreTeachingBubble(false);
},
}}
>
{t(Keys.splashScreen.teachingBubble.newToPostgres.body)}
Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you can find
sample data, query.
</TeachingBubble>
)}
{/*TODO: convert below to use SplashScreenButton */}
@@ -348,7 +349,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
))}
{userContext.apiType === "Postgres" && usePostgres.getState().showResetPasswordBubble && (
<TeachingBubble
headline={t(Keys.splashScreen.teachingBubble.resetPassword.headline)}
headline="Create your password"
target={"#mainButton-quickstartDescription"}
hasCloseButton
onDismiss={() => {
@@ -363,7 +364,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
preventDismissOnScroll: true,
}}
primaryButtonProps={{
text: t(Keys.common.create),
text: "Create",
onClick: () => {
localStorage.setItem(userContext.databaseAccount.id, "true");
sendMessage({
@@ -373,7 +374,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
},
}}
>
{t(Keys.splashScreen.teachingBubble.resetPassword.body)}
If you haven&apos;t changed your password yet, change it now.
</TeachingBubble>
)}
</div>
@@ -392,8 +393,8 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
const launchQuickstartBtn = {
id: "quickstartDescription",
iconSrc: QuickStartIcon,
title: t(Keys.splashScreen.quickStart.title),
description: t(Keys.splashScreen.quickStart.description),
title: "Launch quick start",
description: "Launch a quick start tutorial to get started with sample data",
onClick: () => {
if (userContext.apiType === "Postgres" || userContext.apiType === "VCoreMongo") {
useTabs.getState().openAndActivateReactTab(ReactTabKind.Quickstart);
@@ -415,8 +416,8 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
if (userContext.apiType === "Postgres") {
return {
iconSrc: PowerShellIcon,
title: t(Keys.splashScreen.shell.postgres.title),
description: t(Keys.splashScreen.shell.postgres.description),
title: "PostgreSQL Shell",
description: "Create table and interact with data using PostgreSQL's shell interface",
onClick: () => container.openNotebookTerminal(TerminalKind.Postgres),
};
}
@@ -424,16 +425,16 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
if (userContext.apiType === "VCoreMongo") {
return {
iconSrc: PowerShellIcon,
title: t(Keys.splashScreen.shell.vcoreMongo.title),
description: t(Keys.splashScreen.shell.vcoreMongo.description),
title: "Mongo Shell",
description: "Create a collection and interact with data using MongoDB's shell interface",
onClick: () => container.openNotebookTerminal(TerminalKind.VCoreMongo),
};
}
return {
iconSrc: ContainersIcon,
title: t(Keys.splashScreen.newCollection.title, { collectionName: getCollectionName() }),
description: t(Keys.splashScreen.newCollection.description),
title: `New ${getCollectionName()}`,
description: "Create a new container for storage and throughput",
onClick: () => {
container.onNewCollectionClicked();
traceOpen(Action.NewContainerHomepage, { apiType: userContext.apiType });
@@ -443,19 +444,19 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
const getThirdCard = (): SplashScreenItem => {
let icon = ConnectIcon;
let title = t(Keys.splashScreen.connectCard.title);
let description = t(Keys.splashScreen.connectCard.description);
let title = "Connect";
let description = "Prefer using your own choice of tooling? Find the connection string you need to connect";
let onClick = () => useTabs.getState().openAndActivateReactTab(ReactTabKind.Connect);
if (userContext.apiType === "Postgres") {
title = t(Keys.splashScreen.connectCard.pgAdmin.title);
description = t(Keys.splashScreen.connectCard.pgAdmin.description);
title = "Connect with pgAdmin";
description = "Prefer pgAdmin? Find your connection strings here";
}
if (userContext.apiType === "VCoreMongo") {
icon = VisualStudioIcon;
title = t(Keys.splashScreen.connectCard.vsCode.title);
description = t(Keys.splashScreen.connectCard.vsCode.description);
title = "Connect with VS Code";
description = "Query and Manage your MongoDB and DocumentDB clusters in Visual Studio Code";
onClick = () => container?.openInVsCode && container.openInVsCode();
}
@@ -484,7 +485,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
info: activity.path,
iconSrc: NotebookIcon,
title: activity.name,
description: t(Keys.splashScreen.sections.notebook),
description: "Notebook",
onClick: () => {
const notebookItem = container.createNotebookContentItemFile(activity.name, activity.path);
notebookItem && container.openNotebook(notebookItem);
@@ -523,18 +524,18 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
items = [
{
link: "https://aka.ms/msl-modeling-partitioning-2",
title: t(Keys.splashScreen.top3Items.sql.advancedModeling.title),
description: t(Keys.splashScreen.top3Items.sql.advancedModeling.description),
title: "Advanced Modeling Patterns",
description: "Learn advanced strategies to optimize your database.",
},
{
link: "https://aka.ms/msl-modeling-partitioning-1",
title: t(Keys.splashScreen.top3Items.sql.partitioning.title),
description: t(Keys.splashScreen.top3Items.sql.partitioning.description),
title: "Partitioning Best Practices",
description: "Learn to apply data model and partitioning strategies.",
},
{
link: "https://aka.ms/msl-resource-planning",
title: t(Keys.splashScreen.top3Items.sql.resourcePlanning.title),
description: t(Keys.splashScreen.top3Items.sql.resourcePlanning.description),
title: "Plan Your Resource Requirements",
description: "Get to know the different configuration choices.",
},
];
break;
@@ -542,18 +543,18 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
items = [
{
link: "https://aka.ms/mongodbintro",
title: t(Keys.splashScreen.top3Items.mongo.whatIsMongo.title),
description: t(Keys.splashScreen.top3Items.mongo.whatIsMongo.description),
title: "What is the MongoDB API?",
description: "Understand Azure Cosmos DB for MongoDB and its features.",
},
{
link: "https://aka.ms/mongodbfeaturesupport",
title: t(Keys.splashScreen.top3Items.mongo.features.title),
description: t(Keys.splashScreen.top3Items.mongo.features.description),
title: "Features and Syntax",
description: "Discover the advantages and features",
},
{
link: "https://aka.ms/mongodbpremigration",
title: t(Keys.splashScreen.top3Items.mongo.migrate.title),
description: t(Keys.splashScreen.top3Items.mongo.migrate.description),
title: "Migrate Your Data",
description: "Pre-migration steps for moving data",
},
];
break;
@@ -561,18 +562,18 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
items = [
{
link: "https://aka.ms/cassandrajava",
title: t(Keys.splashScreen.top3Items.cassandra.buildJavaApp.title),
description: t(Keys.splashScreen.top3Items.cassandra.buildJavaApp.description),
title: "Build a Java App",
description: "Create a Java app using an SDK.",
},
{
link: "https://aka.ms/cassandrapartitioning",
title: t(Keys.splashScreen.top3Items.cassandra.partitioning.title),
description: t(Keys.splashScreen.top3Items.cassandra.partitioning.description),
title: "Partitioning Best Practices",
description: "Learn how partitioning works.",
},
{
link: "https://aka.ms/cassandraRu",
title: t(Keys.splashScreen.top3Items.cassandra.requestUnits.title),
description: t(Keys.splashScreen.top3Items.cassandra.requestUnits.description),
title: "Request Units (RUs)",
description: "Understand RU charges.",
},
];
break;
@@ -580,18 +581,18 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
items = [
{
link: "https://aka.ms/Graphdatamodeling",
title: t(Keys.splashScreen.top3Items.gremlin.dataModeling.title),
description: t(Keys.splashScreen.top3Items.gremlin.dataModeling.description),
title: "Data Modeling",
description: "Graph data modeling recommendations",
},
{
link: "https://aka.ms/graphpartitioning",
title: t(Keys.splashScreen.top3Items.gremlin.partitioning.title),
description: t(Keys.splashScreen.top3Items.gremlin.partitioning.description),
title: "Partitioning Best Practices",
description: "Learn how partitioning works",
},
{
link: "https://aka.ms/graphapiquery",
title: t(Keys.splashScreen.top3Items.gremlin.queryData.title),
description: t(Keys.splashScreen.top3Items.gremlin.queryData.description),
title: "Query Data",
description: "Querying data with Gremlin",
},
];
break;
@@ -599,18 +600,18 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
items = [
{
link: "https://aka.ms/tableintro",
title: t(Keys.splashScreen.top3Items.tables.whatIsTable.title),
description: t(Keys.splashScreen.top3Items.tables.whatIsTable.description),
title: "What is the Table API?",
description: "Understand Azure Cosmos DB for Table and its features",
},
{
link: "https://aka.ms/tableimport",
title: t(Keys.splashScreen.top3Items.tables.migrate.title),
description: t(Keys.splashScreen.top3Items.tables.migrate.description),
title: "Migrate your data",
description: "Learn how to migrate your data",
},
{
link: "https://aka.ms/tablefaq",
title: t(Keys.splashScreen.top3Items.tables.faq.title),
description: t(Keys.splashScreen.top3Items.tables.faq.description),
title: "Azure Cosmos DB for Table FAQs",
description: "Common questions about Azure Cosmos DB for Table",
},
];
break;
@@ -667,7 +668,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
</ul>
{recentItems.length > 0 && (
<Link onClick={() => clearMostRecent()} className={styles.listItemTitle}>
{t(Keys.splashScreen.sections.clearRecents)}
Clear Recents
</Link>
)}
</Stack>
@@ -682,15 +683,15 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
}
const cdbLiveTv: item = {
link: "https://developer.azurecosmosdb.com/tv",
title: t(Keys.splashScreen.learningResources.liveTv.title),
description: t(Keys.splashScreen.learningResources.liveTv.description),
title: "Learn the Fundamentals",
description: "Watch Azure Cosmos DB Live TV show introductory and how to videos.",
};
const commonItems: item[] = [
{
link: "https://learn.microsoft.com/azure/cosmos-db/data-explorer-shortcuts",
title: t(Keys.splashScreen.learningResources.shortcuts.title),
description: t(Keys.splashScreen.learningResources.shortcuts.description),
title: "Data Explorer keyboard shortcuts",
description: "Learn keyboard shortcuts to navigate Data Explorer.",
},
];
@@ -701,14 +702,14 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
apiItems = [
{
link: "https://aka.ms/msl-sdk-connect",
title: t(Keys.splashScreen.learningResources.sql.sdk.title),
description: t(Keys.splashScreen.learningResources.sql.sdk.description),
title: "Get Started using an SDK",
description: "Learn about the Azure Cosmos DB SDK.",
},
cdbLiveTv,
{
link: "https://aka.ms/msl-move-data",
title: t(Keys.splashScreen.learningResources.sql.migrate.title),
description: t(Keys.splashScreen.learningResources.sql.migrate.description),
title: "Migrate Your Data",
description: "Migrate data using Azure services and open-source solutions.",
},
];
break;
@@ -716,13 +717,13 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
apiItems = [
{
link: "https://aka.ms/mongonodejs",
title: t(Keys.splashScreen.learningResources.mongo.nodejs.title),
description: t(Keys.splashScreen.learningResources.mongo.nodejs.description),
title: "Build an app with Node.js",
description: "Create a Node.js app.",
},
{
link: "https://aka.ms/mongopython",
title: t(Keys.splashScreen.learningResources.mongo.gettingStarted.title),
description: t(Keys.splashScreen.learningResources.mongo.gettingStarted.description),
title: "Getting Started Guide",
description: "Learn the basics to get started.",
},
cdbLiveTv,
];
@@ -731,14 +732,14 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
apiItems = [
{
link: "https://aka.ms/cassandracontainer",
title: t(Keys.splashScreen.learningResources.cassandra.createContainer.title),
description: t(Keys.splashScreen.learningResources.cassandra.createContainer.description),
title: "Create a Container",
description: "Get to know the create a container options.",
},
cdbLiveTv,
{
link: "https://aka.ms/Cassandrathroughput",
title: t(Keys.splashScreen.learningResources.cassandra.throughput.title),
description: t(Keys.splashScreen.learningResources.cassandra.throughput.description),
title: "Provision Throughput",
description: "Learn how to configure throughput.",
},
];
break;
@@ -746,13 +747,13 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
apiItems = [
{
link: "https://aka.ms/graphquickstart",
title: t(Keys.splashScreen.learningResources.gremlin.getStarted.title),
description: t(Keys.splashScreen.learningResources.gremlin.getStarted.description),
title: "Get Started ",
description: "Create, query, and traverse using the Gremlin console",
},
{
link: "https://aka.ms/graphimport",
title: t(Keys.splashScreen.learningResources.gremlin.importData.title),
description: t(Keys.splashScreen.learningResources.gremlin.importData.description),
title: "Import Graph Data",
description: "Learn Bulk ingestion data using BulkExecutor",
},
cdbLiveTv,
];
@@ -761,13 +762,13 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
apiItems = [
{
link: "https://aka.ms/tabledotnet",
title: t(Keys.splashScreen.learningResources.tables.dotnet.title),
description: t(Keys.splashScreen.learningResources.tables.dotnet.description),
title: "Build a .NET App",
description: "How to access Azure Cosmos DB for Table from a .NET app.",
},
{
link: "https://aka.ms/Tablejava",
title: t(Keys.splashScreen.learningResources.tables.java.title),
description: t(Keys.splashScreen.learningResources.tables.java.description),
title: "Build a Java App",
description: "Create a Azure Cosmos DB for Table app with Java SDK ",
},
cdbLiveTv,
];
@@ -806,17 +807,17 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
const postgresNextStepItems: { link: string; title: string; description: string }[] = [
{
link: "https://go.microsoft.com/fwlink/?linkid=2208312",
title: t(Keys.splashScreen.nextStepItems.postgres.dataModeling),
title: "Data Modeling",
description: "",
},
{
link: " https://go.microsoft.com/fwlink/?linkid=2206941 ",
title: t(Keys.splashScreen.nextStepItems.postgres.distributionColumn),
title: "How to choose a Distribution Column",
description: "",
},
{
link: "https://go.microsoft.com/fwlink/?linkid=2207425",
title: t(Keys.splashScreen.nextStepItems.postgres.buildApps),
title: "Build Apps with Python/Java/Django",
description: "",
},
];
@@ -824,17 +825,17 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
const vcoreMongoNextStepItems: { link: string; title: string; description: string }[] = [
{
link: "https://learn.microsoft.com/azure/cosmos-db/mongodb/vcore/migration-options",
title: t(Keys.splashScreen.nextStepItems.vcoreMongo.migrateData),
title: "Migrate Data",
description: "",
},
{
link: "https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/vcore/vector-search-ai",
title: t(Keys.splashScreen.nextStepItems.vcoreMongo.vectorSearch),
title: "Build AI apps with Vector Search",
description: "",
},
{
link: "https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/vcore/tutorial-nodejs-web-app?tabs=github-codespaces",
title: t(Keys.splashScreen.nextStepItems.vcoreMongo.buildApps),
title: "Build Apps with Nodejs",
description: "",
},
];
@@ -862,17 +863,17 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
const postgresLearnMoreItems: { link: string; title: string; description: string }[] = [
{
link: "https://go.microsoft.com/fwlink/?linkid=2207226",
title: t(Keys.splashScreen.learnMoreItems.postgres.performanceTuning),
title: "Performance Tuning",
description: "",
},
{
link: "https://go.microsoft.com/fwlink/?linkid=2208037",
title: t(Keys.splashScreen.learnMoreItems.postgres.diagnosticQueries),
title: "Useful Diagnostic Queries",
description: "",
},
{
link: "https://go.microsoft.com/fwlink/?linkid=2205270",
title: t(Keys.splashScreen.learnMoreItems.postgres.sqlReference),
title: "Distributed SQL Reference",
description: "",
},
];
@@ -880,17 +881,17 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
const vcoreMongoLearnMoreItems: { link: string; title: string; description: string }[] = [
{
link: "https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/vcore/vector-search",
title: t(Keys.splashScreen.learnMoreItems.vcoreMongo.vectorSearch),
title: "Vector Search",
description: "",
},
{
link: "https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/vcore/how-to-create-text-index",
title: t(Keys.splashScreen.learnMoreItems.vcoreMongo.textIndexing),
title: "Text Indexing",
description: "",
},
{
link: "https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/vcore/troubleshoot-common-issues",
title: t(Keys.splashScreen.learnMoreItems.vcoreMongo.troubleshoot),
title: "Troubleshoot common issues",
description: "",
},
];
@@ -931,25 +932,24 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
persistentBeak
>
<TeachingBubbleContent
headline={t(Keys.splashScreen.teachingBubble.coachMark.headline, {
collectionName: getCollectionName().toLocaleLowerCase(),
})}
headline={`Start with sample ${getCollectionName().toLocaleLowerCase()}`}
hasCloseButton
closeButtonAriaLabel={t(Keys.common.close)}
closeButtonAriaLabel="Close"
primaryButtonProps={{
text: t(Keys.common.getStarted),
text: "Get started",
onClick: () => {
useCarousel.getState().setShowCoachMark(false);
container.onNewCollectionClicked({ isQuickstart: true });
},
}}
secondaryButtonProps={{
text: t(Keys.common.cancel),
text: "Cancel",
onClick: () => useCarousel.getState().setShowCoachMark(false),
}}
onDismiss={() => useCarousel.getState().setShowCoachMark(false)}
>
{t(Keys.splashScreen.teachingBubble.coachMark.body)}
You will be guided to create a sample container with sample data, then we will give you a tour of data
explorer. You can also cancel launching this tour and explore yourself
</TeachingBubbleContent>
</Coachmark>
)}
@@ -963,7 +963,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
fontFamily: '"Segoe UI Semibold", "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif',
}}
>
{t(Keys.splashScreen.sections.nextSteps)}
Next steps
</Text>
{getNextStepItems()}
</Stack>
@@ -975,7 +975,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
fontFamily: '"Segoe UI Semibold", "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif',
}}
>
{t(Keys.splashScreen.sections.tipsAndLearnMore)}
Tips & learn more
</Text>
{getTipsAndLearnMoreItems()}
</Stack>
@@ -984,15 +984,15 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
) : (
<div className={styles.moreStuffContainer}>
<div className={styles.moreStuffColumn}>
<h2 className={styles.columnTitle}>{t(Keys.splashScreen.sections.recents)}</h2>
<h2 className={styles.columnTitle}>Recents</h2>
{getRecentItems()}
</div>
<div className={styles.moreStuffColumn}>
<h2 className={styles.columnTitle}>{t(Keys.splashScreen.sections.top3)}</h2>
<h2 className={styles.columnTitle}>Top 3 things you need to know</h2>
{top3Items()}
</div>
<div className={styles.moreStuffColumn}>
<h2 className={styles.columnTitle}>{t(Keys.splashScreen.sections.learningResources)}</h2>
<h2 className={styles.columnTitle}>Learning Resources</h2>
{getLearningResourceItems()}
</div>
</div>

View File

@@ -18,8 +18,6 @@ import { queryConflicts } from "../../Common/dataAccess/queryConflicts";
import { updateDocument } from "../../Common/dataAccess/updateDocument";
import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { Keys } from "../../Localization/Keys.generated";
import { t } from "../../Localization/t";
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
@@ -59,7 +57,7 @@ export default class ConflictsTab extends TabsBase {
private _documentsIterator: MinimalQueryIterator;
private _container: Explorer;
private _acceptButtonLabel: ko.Observable<string> = ko.observable(t(Keys.common.save));
private _acceptButtonLabel: ko.Observable<string> = ko.observable("Save");
constructor(options: ViewModels.ConflictsTabOptions) {
super(options);
@@ -215,9 +213,9 @@ export default class ConflictsTab extends TabsBase {
this.selectedConflictContent.subscribe((newContent: string) => this._onEditorContentChange(newContent));
this.conflictOperation.subscribe((newOperationType: string) => {
let operationLabel = t(Keys.common.save);
let operationLabel = "Save";
if (newOperationType === Constants.ConflictOperationType.Replace) {
operationLabel = t(Keys.common.update);
operationLabel = "Update";
}
this._acceptButtonLabel(operationLabel);
@@ -231,7 +229,7 @@ export default class ConflictsTab extends TabsBase {
this._documentsIterator = this.createIterator();
await this.loadNextPage();
} catch (error) {
useDialog.getState().showOkModalDialog(t(Keys.tabs.conflicts.refreshGridFailed), getErrorMessage(error));
useDialog.getState().showOkModalDialog("Refresh documents grid failed", getErrorMessage(error));
}
}
@@ -259,11 +257,11 @@ export default class ConflictsTab extends TabsBase {
useDialog
.getState()
.showOkCancelModalDialog(
t(Keys.tabs.conflicts.unsavedChanges),
t(Keys.tabs.conflicts.changesWillBeLost),
t(Keys.common.ok),
"Unsaved changes",
"Changes will be lost. Do you want to continue?",
"OK",
async () => await this.resolveConflict(),
t(Keys.common.cancel),
"Cancel",
undefined,
);
} else {
@@ -334,7 +332,7 @@ export default class ConflictsTab extends TabsBase {
} catch (error) {
this.isExecutionError(true);
const errorMessage = getErrorMessage(error);
useDialog.getState().showOkModalDialog(t(Keys.tabs.conflicts.resolveConflictFailed), errorMessage);
useDialog.getState().showOkModalDialog("Resolve conflict failed", errorMessage);
TelemetryProcessor.traceFailure(
Action.ResolveConflict,
{
@@ -388,7 +386,7 @@ export default class ConflictsTab extends TabsBase {
} catch (error) {
this.isExecutionError(true);
const errorMessage = getErrorMessage(error);
useDialog.getState().showOkModalDialog(t(Keys.tabs.conflicts.deleteConflictFailed), errorMessage);
useDialog.getState().showOkModalDialog("Delete conflict failed", errorMessage);
TelemetryProcessor.traceFailure(
Action.DeleteConflict,
{
@@ -619,7 +617,7 @@ export default class ConflictsTab extends TabsBase {
}
if (this.discardButton.visible()) {
const label = t(Keys.common.discard);
const label = "Discard";
buttons.push({
iconSrc: DiscardIcon,
iconAlt: label,
@@ -632,7 +630,7 @@ export default class ConflictsTab extends TabsBase {
}
if (this.deleteButton.visible()) {
const label = t(Keys.common.delete);
const label = "Delete";
buttons.push({
iconSrc: DeleteIcon,
iconAlt: label,

View File

@@ -41,8 +41,6 @@ import { usePrevious } from "Explorer/Tabs/DocumentsTabV2/SelectionHelper";
import { CosmosFluentProvider, LayoutConstants, cosmosShorthands, tokens } from "Explorer/Theme/ThemeUtil";
import { useSelectedNode } from "Explorer/useSelectedNode";
import { KeyboardAction, KeyboardActionGroup, useKeyboardActionGroup } from "KeyboardShortcuts";
import { Keys } from "Localization/Keys.generated";
import { t } from "Localization/t";
import { isFabric } from "Platform/Fabric/FabricUtil";
import { QueryConstants } from "Shared/Constants";
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
@@ -351,7 +349,7 @@ export const getTabsButtons = ({
}
const buttons: CommandButtonComponentProps[] = [];
const label = !isPreferredApiMongoDB ? t(Keys.tabs.documents.newItem) : t(Keys.tabs.documents.newDocument);
const label = !isPreferredApiMongoDB ? "New Item" : "New Document";
if (getNewDocumentButtonState(editorState).visible) {
buttons.push({
iconSrc: NewDocumentIcon,
@@ -370,7 +368,7 @@ export const getTabsButtons = ({
}
if (getSaveNewDocumentButtonState(editorState).visible) {
const label = t(Keys.common.save);
const label = "Save";
buttons.push({
iconSrc: SaveIcon,
iconAlt: label,
@@ -388,7 +386,7 @@ export const getTabsButtons = ({
}
if (getDiscardNewDocumentChangesButtonState(editorState).visible) {
const label = t(Keys.common.discard);
const label = "Discard";
buttons.push({
iconSrc: DiscardIcon,
iconAlt: label,
@@ -405,7 +403,7 @@ export const getTabsButtons = ({
}
if (getSaveExistingDocumentButtonState(editorState).visible) {
const label = t(Keys.common.update);
const label = "Update";
buttons.push({
iconSrc: SaveIcon,
iconAlt: label,
@@ -423,7 +421,7 @@ export const getTabsButtons = ({
}
if (getDiscardExistingDocumentChangesButtonState(editorState).visible) {
const label = t(Keys.common.discard);
const label = "Discard";
buttons.push({
iconSrc: DiscardIcon,
iconAlt: label,
@@ -440,7 +438,7 @@ export const getTabsButtons = ({
}
if (selectedRows.size > 0) {
const label = t(Keys.common.delete);
const label = "Delete";
buttons.push({
iconSrc: DeleteDocumentIcon,
iconAlt: label,
@@ -455,7 +453,7 @@ export const getTabsButtons = ({
}
if (!isPreferredApiMongoDB) {
const label = t(Keys.tabs.documents.uploadItem);
const label = "Upload Item";
buttons.push({
id: UPLOAD_BUTTON_ID,
iconSrc: UploadIcon,
@@ -739,18 +737,17 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
} else if (result.statusCode >= 400) {
newFailed.push(result.documentId);
logConsoleError(
t(Keys.tabs.documents.deleteDocumentFailedLog, {
documentId: result.documentId.id(),
statusCode: result.statusCode,
}),
`Failed to delete document ${result.documentId.id()} with status code ${result.statusCode}`,
);
}
});
logConsoleInfo(t(Keys.tabs.documents.deleteSuccessLog, { count: newSuccessful.length }));
logConsoleInfo(`Successfully deleted ${newSuccessful.length} document(s)`);
if (newThrottled.length > 0) {
logConsoleError(t(Keys.tabs.documents.deleteThrottledLog, { count: newThrottled.length }));
logConsoleError(
`Failed to delete ${newThrottled.length} document(s) due to "Request too large" (429) error. Retrying...`,
);
}
// Update result of the bulk delete: method is called again, because the state variables changed
@@ -792,7 +789,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
);
let partitionKeyProperties = useMemo(() => {
return partitionKeyPropertyHeaders?.map((partitionKeyPropertyHeader) =>
partitionKeyPropertyHeader.replace(/[/]+/g, ".").substring(1).replace(/[']+/g, "").replace(/["]+/g, ""),
partitionKeyPropertyHeader.replace(/[/]+/g, ".").substring(1).replace(/[']+/g, ""),
);
}, [partitionKeyPropertyHeaders]);
@@ -920,11 +917,11 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
useDialog
.getState()
.showOkCancelModalDialog(
t(Keys.tabs.documents.unsavedChanges),
t(Keys.tabs.documents.unsavedChangesMessage),
t(Keys.common.ok),
"Unsaved changes",
"Your unsaved changes will be lost. Do you want to continue?",
"OK",
onDiscard,
t(Keys.common.cancel),
"Cancel",
onCancelDiscard,
);
} else {
@@ -1014,7 +1011,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
(error) => {
onExecutionErrorChange(true);
const errorMessage = getErrorMessage(error);
useDialog.getState().showOkModalDialog(t(Keys.tabs.documents.createDocumentFailed), errorMessage);
useDialog.getState().showOkModalDialog("Create document failed", errorMessage);
TelemetryProcessor.traceFailure(
Action.CreateDocument,
{
@@ -1100,7 +1097,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
selectedDocumentId.partitionKeyValue = originalPartitionKeyValue;
onExecutionErrorChange(true);
const errorMessage = getErrorMessage(error);
useDialog.getState().showOkModalDialog(t(Keys.tabs.documents.updateDocumentFailed), errorMessage);
useDialog.getState().showOkModalDialog("Update document failed", errorMessage);
TelemetryProcessor.traceFailure(
Action.UpdateDocument,
{
@@ -1177,12 +1174,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
// Remove the check for systemKey, remove call to deleteNoSqlDocument(). deleteNoSqlDocuments() should
// always be called for NoSQL.
deletePromise = deleteNoSqlDocument(_collection, toDeleteDocumentIds[0]).then(() => {
useDialog
.getState()
.showOkModalDialog(
t(Keys.tabs.documents.deleteDocumentDialogTitle),
t(Keys.tabs.documents.documentDeleted),
);
useDialog.getState().showOkModalDialog("Delete document", "Document successfully deleted.");
return [toDeleteDocumentIds[0]];
});
// ----------------------------------------------------------------------------------------------------
@@ -1259,20 +1251,17 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
useDialog
.getState()
.showOkModalDialog(
t(Keys.tabs.documents.deleteDocumentsDialogTitle),
t(Keys.tabs.documents.throttlingError),
"Delete documents",
`Some documents failed to delete due to a rate limiting error. Please try again later. To prevent this in the future, consider increasing the throughput on your container or database.`,
{
linkText: t(Keys.common.learnMore),
linkText: "Learn More",
linkUrl: MONGO_THROTTLING_DOC_URL,
},
);
} else {
useDialog
.getState()
.showOkModalDialog(
t(Keys.tabs.documents.deleteDocumentsDialogTitle),
t(Keys.tabs.documents.deleteFailed, { error: error.message }),
);
.showOkModalDialog("Delete documents", `Deleting document(s) failed (${error.message})`);
}
},
)
@@ -1286,21 +1275,21 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
const isPlural = selectedRows.size > 1;
const documentName = !isPreferredApiMongoDB
? isPlural
? t(Keys.tabs.documents.selectedItems, { count: selectedRows.size })
: t(Keys.tabs.documents.selectedItem)
? `the selected ${selectedRows.size} items`
: "the selected item"
: isPlural
? t(Keys.tabs.documents.selectedDocuments, { count: selectedRows.size })
: t(Keys.tabs.documents.selectedDocument);
const msg = t(Keys.tabs.documents.confirmDelete, { documentName });
? `the selected ${selectedRows.size} documents`
: "the selected document";
const msg = `Are you sure you want to delete ${documentName}?`;
useDialog
.getState()
.showOkCancelModalDialog(
t(Keys.tabs.documents.confirmDeleteTitle),
"Confirm delete",
msg,
t(Keys.common.delete),
"Delete",
() => deleteDocuments(Array.from(selectedRows).map((index) => documentIds[index as number])),
t(Keys.common.cancel),
"Cancel",
undefined,
);
}, [deleteDocuments, documentIds, isPreferredApiMongoDB, selectedRows]);
@@ -1481,11 +1470,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
const partitionKey = _partitionKey || (_collection && _collection.partitionKey);
const partitionKeyPropertyHeaders = _collection?.partitionKeyPropertyHeaders || partitionKey?.paths;
const partitionKeyProperties = partitionKeyPropertyHeaders?.map((partitionKeyPropertyHeader) =>
partitionKeyPropertyHeader
.replace(/[/]+/g, ".")
.substring(1)
.replace(/[']+/g, "")
.replace(/["]+/g, ""),
partitionKeyPropertyHeader.replace(/[/]+/g, ".").substring(1).replace(/[']+/g, ""),
);
return newDocumentId(rawDocument, partitionKeyProperties, partitionKeyValue);
@@ -1834,8 +1819,8 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
const partitionKeyProperty = partitionKeyProperties?.[0];
if (partitionKeyProperty !== "_id" && !_hasShardKeySpecified(documentContent)) {
const message = t(Keys.tabs.documents.missingShardProperty, { partitionKeyProperty });
useDialog.getState().showOkModalDialog(t(Keys.tabs.documents.createDocumentFailed), message);
const message = `The document is lacking the shard property: ${partitionKeyProperty}`;
useDialog.getState().showOkModalDialog("Create document failed", message);
onExecutionErrorChange(true);
TelemetryProcessor.traceFailure(
Action.CreateDocument,
@@ -1846,7 +1831,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
},
startKey,
);
Logger.logError(t(Keys.tabs.documents.missingShardKeyLog), "MongoDocumentsTab");
Logger.logError("Failed to save new document: Document shard key not defined", "MongoDocumentsTab");
throw new Error("Document without shard key");
}
@@ -1889,7 +1874,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
(error) => {
onExecutionErrorChange(true);
const errorMessage = getErrorMessage(error);
useDialog.getState().showOkModalDialog(t(Keys.tabs.documents.createDocumentFailed), errorMessage);
useDialog.getState().showOkModalDialog("Create document failed", errorMessage);
TelemetryProcessor.traceFailure(
Action.CreateDocument,
{
@@ -1960,7 +1945,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
(error) => {
onExecutionErrorChange(true);
const errorMessage = getErrorMessage(error);
useDialog.getState().showOkModalDialog(t(Keys.tabs.documents.updateDocumentFailed), errorMessage);
useDialog.getState().showOkModalDialog("Update document failed", errorMessage);
TelemetryProcessor.traceFailure(
Action.UpdateDocument,
{
@@ -2069,7 +2054,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
}
} catch (error) {
console.error(error);
useDialog.getState().showOkModalDialog(t(Keys.tabs.documents.refreshGridFailed), getErrorMessage(error));
useDialog.getState().showOkModalDialog("Refresh documents grid failed", getErrorMessage(error));
}
},
[createIterator, filterContent],
@@ -2081,17 +2066,18 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
* @returns 429 warning message
*/
const get429WarningMessageNoSql = (): string => {
let message = t(Keys.tabs.documents.requestTooLargeBase);
let message = 'Some delete requests failed due to a "Request too large" exception (429)';
if (bulkDeleteOperation.count === bulkDeleteProcess.successfulIds.length) {
message += ", " + t(Keys.tabs.documents.retriedSuccessfully);
message += ", but were successfully retried.";
} else if (bulkDeleteMode === "inProgress" || bulkDeleteMode === "aborting") {
message += ". " + t(Keys.tabs.documents.retryingNow);
message += ". Retrying now.";
} else {
message += ".";
}
return (message += " " + t(Keys.tabs.documents.increaseThroughputTip));
return (message +=
" To prevent this in the future, consider increasing the throughput on your container or database.");
};
const onColumnSelectionChange = (newSelectedColumnIds: string[]): void => {
@@ -2138,7 +2124,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
const nonBlankLastFilters = lastFilterContents.filter((filter) => filter.trim() !== "");
if (nonBlankLastFilters.length > 0) {
options.push({
label: t(Keys.tabs.documents.savedFilters),
label: "Saved filters",
options: nonBlankLastFilters,
});
}
@@ -2167,14 +2153,14 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
dropdownOptions={getFilterChoices()}
placeholder={
isPreferredApiMongoDB
? t(Keys.tabs.documents.mongoFilterPlaceholder)
: t(Keys.tabs.documents.sqlFilterPlaceholder)
? "Type a query predicate (e.g., {´a´:´foo´}), or choose one from the drop down list, or leave empty to query all documents."
: "Type a query predicate (e.g., WHERE c.id=´1´), or choose one from the drop down list, or leave empty to query all documents."
}
title={t(Keys.tabs.documents.filterTooltip)}
title="Type a query predicate or choose one from the list."
value={filterContent}
onChange={updateFilterContent}
onKeyDown={onFilterKeyDown}
bottomLink={{ text: t(Keys.common.learnMore), url: DATA_EXPLORER_DOC_URL }}
bottomLink={{ text: "Learn more", url: DATA_EXPLORER_DOC_URL }}
/>
<Button
appearance="primary"
@@ -2190,12 +2176,10 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
}
}}
disabled={isExecuting && isPreferredApiMongoDB}
aria-label={
!isExecuting || isPreferredApiMongoDB ? t(Keys.tabs.documents.applyFilter) : t(Keys.common.cancel)
}
aria-label={!isExecuting || isPreferredApiMongoDB ? "Apply filter" : "Cancel"}
tabIndex={0}
>
{!isExecuting || isPreferredApiMongoDB ? t(Keys.tabs.documents.applyFilter) : t(Keys.common.cancel)}
{!isExecuting || isPreferredApiMongoDB ? "Apply Filter" : "Cancel"}
</Button>
</div>
<Allotment
@@ -2239,14 +2223,14 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
</div>
{tableContainerSizePx?.width >= calculateOffset(selectedColumnIds.length) + 200 && (
<div
title={t(Keys.common.refresh)}
title="Refresh"
className={styles.refreshBtn}
role="button"
onClick={() => refreshDocumentsGrid(false)}
aria-label={t(Keys.common.refresh)}
aria-label="Refresh"
tabIndex={0}
>
<img src={RefreshIcon} alt={t(Keys.common.refresh)} />
<img src={RefreshIcon} alt="Refresh" />
</div>
)}
</div>
@@ -2259,7 +2243,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
onClick={() => loadNextPage(documentsIterator.iterator, false)}
onKeyDown={onLoadMoreKeyInput}
>
{t(Keys.tabs.documents.loadMore)}
Load more
</a>
)}
</div>
@@ -2271,7 +2255,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
language={"json"}
content={selectedDocumentContent}
isReadOnly={false}
ariaLabel={t(Keys.tabs.documents.documentEditor)}
ariaLabel={"Document editor"}
lineNumbers={"on"}
theme={"_theme"}
onContentChanged={_onEditorContentChange}
@@ -2279,9 +2263,7 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
/>
)}
{selectedRows.size > 1 && (
<span style={{ margin: 10 }}>
{t(Keys.tabs.documents.numberOfSelectedDocuments, { count: selectedRows.size })}
</span>
<span style={{ margin: 10 }}>Number of selected documents: {selectedRows.size}</span>
)}
</div>
</Allotment.Pane>
@@ -2290,43 +2272,42 @@ export const DocumentsTabComponent: React.FunctionComponent<IDocumentsTabCompone
{bulkDeleteOperation && (
<ProgressModalDialog
isOpen={isBulkDeleteDialogOpen}
dismissText={t(Keys.tabs.documents.abort)}
dismissText="Abort"
onDismiss={() => {
setIsBulkDeleteDialogOpen(false);
setBulkDeleteOperation(undefined);
}}
onCancel={() => setBulkDeleteMode("aborting")}
title={t(Keys.tabs.documents.deletingDocuments, { count: bulkDeleteOperation.count })}
message={t(Keys.tabs.documents.deletedDocumentsSuccess, { count: bulkDeleteProcess.successfulIds.length })}
title={`Deleting ${bulkDeleteOperation.count} document(s)`}
message={`Successfully deleted ${bulkDeleteProcess.successfulIds.length} document(s).`}
maxValue={bulkDeleteOperation.count}
value={bulkDeleteProcess.successfulIds.length}
mode={bulkDeleteMode}
>
<div className={styles.deleteProgressContent}>
{(bulkDeleteMode === "aborting" || bulkDeleteMode === "aborted") && (
<div style={{ paddingBottom: tokens.spacingVerticalL }}>{t(Keys.tabs.documents.deleteAborted)}</div>
<div style={{ paddingBottom: tokens.spacingVerticalL }}>Deleting document(s) was aborted.</div>
)}
{(bulkDeleteProcess.failedIds.length > 0 ||
(bulkDeleteProcess.throttledIds.length > 0 && bulkDeleteMode !== "inProgress")) && (
<MessageBar intent="error" style={{ marginBottom: tokens.spacingVerticalL }}>
<MessageBarBody>
<MessageBarTitle>{t(Keys.tabs.documents.error)}</MessageBarTitle>
{t(Keys.tabs.documents.failedToDeleteDocuments, {
count:
bulkDeleteMode === "inProgress"
? bulkDeleteProcess.failedIds.length
: bulkDeleteProcess.failedIds.length + bulkDeleteProcess.throttledIds.length,
})}
<MessageBarTitle>Error</MessageBarTitle>
Failed to delete{" "}
{bulkDeleteMode === "inProgress"
? bulkDeleteProcess.failedIds.length
: bulkDeleteProcess.failedIds.length + bulkDeleteProcess.throttledIds.length}{" "}
document(s).
</MessageBarBody>
</MessageBar>
)}
{bulkDeleteProcess.hasBeenThrottled && (
<MessageBar intent="warning">
<MessageBarBody>
<MessageBarTitle>{t(Keys.tabs.documents.warning)}</MessageBarTitle>
<MessageBarTitle>Warning</MessageBarTitle>
{get429WarningMessageNoSql()}{" "}
<Link href={NO_SQL_THROTTLING_DOC_URL} target="_blank">
{t(Keys.common.learnMore)}
Learn More
</Link>
</MessageBarBody>
</MessageBar>

View File

@@ -44,13 +44,13 @@ exports[`Documents tab (noSql API) when rendered should render the page 1`] = `
}
onChange={[Function]}
onKeyDown={[Function]}
placeholder="Type a query predicate (e.g., WHERE c.id="1"), or choose one from the drop down list, or leave empty to query all documents."
placeholder="Type a query predicate (e.g., WHERE c.id=´1´), or choose one from the drop down list, or leave empty to query all documents."
title="Type a query predicate or choose one from the list."
value=""
/>
<Button
appearance="primary"
aria-label="Apply Filter"
aria-label="Apply filter"
data-test="DocumentsTab/ApplyFilter"
disabled={false}
onClick={[Function]}

View File

@@ -1,8 +1,6 @@
import React, { Component } from "react";
import { configContext } from "../../../ConfigContext";
import * as ViewModels from "../../../Contracts/ViewModels";
import { Keys } from "../../../Localization/Keys.generated";
import { t } from "../../../Localization/t";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../../UserContext";
@@ -214,7 +212,7 @@ export default class MongoShellTabComponent extends Component<
src={this.state.url}
id={this.props.tabsBaseInstance.tabId}
onLoad={(event) => this.setContentFocus(event)}
title={t(Keys.tabs.mongoShell.title)}
title="Mongo Shell"
role="tabpanel"
></iframe>
);

View File

@@ -17,8 +17,6 @@ import { QueryTabStyles, useQueryTabStyles } from "Explorer/Tabs/QueryTab/Styles
import { CosmosFluentProvider } from "Explorer/Theme/ThemeUtil";
import { useSelectedNode } from "Explorer/useSelectedNode";
import { KeyboardAction } from "KeyboardShortcuts";
import { Keys } from "Localization/Keys.generated";
import { t } from "Localization/t";
import { QueryConstants } from "Shared/Constants";
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
import { Action } from "Shared/Telemetry/TelemetryConstants";
@@ -317,9 +315,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
};
public onSaveQueryClick = (): void => {
useSidePanel
.getState()
.openSidePanel(t(Keys.tabs.query.saveQuery), <SaveQueryPane explorer={this.props.collection.container} />);
useSidePanel.getState().openSidePanel("Save Query", <SaveQueryPane explorer={this.props.collection.container} />);
};
public launchQueryCopilotChat = (): void => {
@@ -329,10 +325,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
public onSavedQueriesClick = (): void => {
useSidePanel
.getState()
.openSidePanel(
t(Keys.tabs.query.openSavedQueries),
<BrowseQueriesPane explorer={this.props.collection.container} />,
);
.openSidePanel("Open Saved Queries", <BrowseQueriesPane explorer={this.props.collection.container} />);
};
public toggleResult(): void {
@@ -480,8 +473,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: CommandButtonComponentProps[] = [];
if (this.executeQueryButton.visible) {
const label =
this.state.selectedContent?.length > 0 ? t(Keys.tabs.query.executeSelection) : t(Keys.tabs.query.executeQuery);
const label = this.state.selectedContent?.length > 0 ? "Execute Selection" : "Execute Query";
buttons.push({
iconSrc: ExecuteQueryIcon,
iconAlt: label,
@@ -498,7 +490,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
if (this.saveQueryButton.visible) {
if (configContext.platform !== Platform.Fabric) {
const label = t(Keys.tabs.query.saveQuery);
const label = "Save Query";
buttons.push({
iconSrc: SaveQueryIcon,
iconAlt: label,
@@ -515,11 +507,11 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
buttons.push({
iconSrc: DownloadQueryIcon,
iconAlt: t(Keys.tabs.query.downloadQuery),
iconAlt: "Download Query",
keyboardAction: KeyboardAction.DOWNLOAD_ITEM,
onCommandClick: this.onDownloadQueryClick,
commandButtonLabel: t(Keys.tabs.query.downloadQuery),
ariaLabel: t(Keys.tabs.query.downloadQuery),
commandButtonLabel: "Download Query",
ariaLabel: "Download Query",
hasPopup: false,
disabled: !this.saveQueryButton.enabled,
});
@@ -576,7 +568,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
// }
if (!this.props.isPreferredApiMongoDB && this.state.isExecuting) {
const label = t(Keys.tabs.query.cancelQuery);
const label = "Cancel query";
buttons.push({
iconSrc: CancelQueryIcon,
iconAlt: label,
@@ -597,23 +589,23 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
const verticalButton: CommandButtonComponentProps = {
isSelected: this.state.queryResultsView === SplitterDirection.Vertical,
iconSrc: this.state.queryResultsView === SplitterDirection.Vertical ? CheckIcon : undefined,
commandButtonLabel: t(Keys.tabs.query.vertical),
ariaLabel: t(Keys.tabs.query.vertical),
commandButtonLabel: "Vertical",
ariaLabel: "Vertical",
onCommandClick: () => this._setViewLayout(SplitterDirection.Vertical),
hasPopup: false,
};
const horizontalButton: CommandButtonComponentProps = {
isSelected: this.state.queryResultsView === SplitterDirection.Horizontal,
iconSrc: this.state.queryResultsView === SplitterDirection.Horizontal ? CheckIcon : undefined,
commandButtonLabel: t(Keys.tabs.query.horizontal),
ariaLabel: t(Keys.tabs.query.horizontal),
commandButtonLabel: "Horizontal",
ariaLabel: "Horizontal",
onCommandClick: () => this._setViewLayout(SplitterDirection.Horizontal),
hasPopup: false,
};
return {
commandButtonLabel: t(Keys.tabs.query.view),
ariaLabel: t(Keys.tabs.query.view),
commandButtonLabel: "View",
ariaLabel: "View",
hasPopup: true,
children: [verticalButton, horizontalButton],
};
@@ -790,7 +782,7 @@ class QueryTabComponentImpl extends React.Component<QueryTabComponentImplProps,
modelMarkers={this.state.modelMarkers}
isReadOnly={false}
wordWrap={"on"}
ariaLabel={t(Keys.tabs.query.editingQuery)}
ariaLabel={"Editing Query"}
lineNumbers={"on"}
theme={this.props.monacoTheme}
onContentChanged={(newContent: string) => this.onChangeContent(newContent)}

View File

@@ -11,8 +11,6 @@ import { createStoredProcedure } from "../../../Common/dataAccess/createStoredPr
import { ExecuteSprocResult } from "../../../Common/dataAccess/executeStoredProcedure";
import { updateStoredProcedure } from "../../../Common/dataAccess/updateStoredProcedure";
import * as ViewModels from "../../../Contracts/ViewModels";
import { Keys } from "../../../Localization/Keys.generated";
import { t } from "../../../Localization/t";
import { useNotificationConsole } from "../../../hooks/useNotificationConsole";
import { useTabs } from "../../../hooks/useTabs";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
@@ -135,7 +133,7 @@ export default class StoredProcedureTabComponent extends React.Component<
this.collection = this.props.collection;
this.executeResultsEditorId = `executestoredprocedureresults${this.props.scriptTabBaseInstance.tabId}`;
this.executeLogsEditorId = `executestoredprocedurelogs${this.props.scriptTabBaseInstance.tabId}`;
this.props.scriptTabBaseInstance.ariaLabel(t(Keys.tabs.storedProcedure.body));
this.props.scriptTabBaseInstance.ariaLabel("Stored Procedure Body");
this.props.iStorProcTabComponentAccessor({
onExecuteSprocsResultEvent: this.onExecuteSprocsResult.bind(this),
@@ -320,7 +318,7 @@ export default class StoredProcedureTabComponent extends React.Component<
protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: CommandButtonComponentProps[] = [];
const label = t(Keys.common.save);
const label = "Save";
if (this.state.saveButton.visible) {
buttons.push({
iconSrc: SaveIcon,
@@ -335,7 +333,7 @@ export default class StoredProcedureTabComponent extends React.Component<
}
if (this.state.updateButton.visible) {
const label = t(Keys.common.update);
const label = "Update";
buttons.push({
iconSrc: SaveIcon,
iconAlt: label,
@@ -349,7 +347,7 @@ export default class StoredProcedureTabComponent extends React.Component<
}
if (this.state.discardButton.visible) {
const label = t(Keys.common.discard);
const label = "Discard";
buttons.push({
iconSrc: DiscardIcon,
iconAlt: label,
@@ -363,7 +361,7 @@ export default class StoredProcedureTabComponent extends React.Component<
}
if (this.state.executeButton.visible) {
const label = t(Keys.common.execute);
const label = "Execute";
buttons.push({
iconSrc: ExecuteQueryIcon,
iconAlt: label,
@@ -521,7 +519,7 @@ export default class StoredProcedureTabComponent extends React.Component<
<div className="tab-pane flexContainer stored-procedure-tab" role="tabpanel">
<div className="storedTabForm flexContainer">
<div className="formTitleFirst">
{t(Keys.tabs.storedProcedure.id)}
Stored Procedure Id
<span className="mandatoryStar" style={{ color: "#ff0707", fontSize: "14px", fontWeight: "bold" }}>
*&nbsp;
</span>
@@ -533,28 +531,28 @@ export default class StoredProcedureTabComponent extends React.Component<
required
pattern={ValidCosmosDbIdInputPattern.source}
title={ValidCosmosDbIdDescription}
aria-label={t(Keys.tabs.storedProcedure.idAriaLabel)}
placeholder={t(Keys.tabs.storedProcedure.idPlaceholder)}
aria-label="Stored procedure id"
placeholder="Enter the new stored procedure id"
size={40}
value={this.state.id}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => this.handleIdOnChange(event)}
/>
</span>
<div className="spUdfTriggerHeader">{t(Keys.tabs.storedProcedure.body)}</div>
<div className="spUdfTriggerHeader">Stored Procedure Body</div>
<EditorReact
language={"javascript"}
content={this.state.sProcEditorContent}
isReadOnly={false}
ariaLabel={t(Keys.tabs.storedProcedure.bodyAriaLabel)}
ariaLabel={"Stored procedure body"}
lineNumbers={"on"}
theme={"_theme"}
onContentChanged={(newContent: string) => this.onChangeContent(newContent)}
/>
{this.state.hasResults && (
<div className="results-container">
<Pivot aria-label={t(Keys.tabs.storedProcedure.successfulExecution)} style={{ height: "100%" }}>
<Pivot aria-label="Successful execution of stored procedure" style={{ height: "100%" }}>
<PivotItem
headerText={t(Keys.common.result)}
headerText="Result"
headerButtonProps={{
"data-order": 1,
"data-title": "Result",
@@ -565,11 +563,11 @@ export default class StoredProcedureTabComponent extends React.Component<
language={"javascript"}
content={this.state.resultData}
isReadOnly={true}
ariaLabel={t(Keys.tabs.storedProcedure.resultAriaLabel)}
ariaLabel={"Execute stored procedure result"}
/>
</PivotItem>
<PivotItem
headerText={t(Keys.tabs.storedProcedure.consoleLogTab)}
headerText="console.log"
headerButtonProps={{
"data-order": 2,
"data-title": "console.log",
@@ -580,7 +578,7 @@ export default class StoredProcedureTabComponent extends React.Component<
language={"javascript"}
content={this.state.logsData}
isReadOnly={true}
ariaLabel={t(Keys.tabs.storedProcedure.logsAriaLabel)}
ariaLabel={"Execute stored procedure logs"}
/>
</PivotItem>
</Pivot>
@@ -588,16 +586,16 @@ export default class StoredProcedureTabComponent extends React.Component<
)}
{this.state.hasErrors && (
<div className="errors-container">
<div className="errors-header">{t(Keys.tabs.storedProcedure.errors)}</div>
<div className="errors-header">Errors:</div>
<div className="errorContent">
<span className="errorMessage">{this.state.error}</span>
<span className="errorDetailsLink">
<a
aria-label={t(Keys.tabs.storedProcedure.errorDetailsAriaLabel)}
aria-label="Error details link"
onClick={() => this.onErrorDetailsClick()}
onKeyPress={(event: React.KeyboardEvent<HTMLAnchorElement>) => this.onErrorDetailsKeyPress(event)}
>
{t(Keys.tabs.storedProcedure.moreDetails)}
More details
</a>
</span>
</div>

View File

@@ -11,8 +11,6 @@ import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils"
import { createTrigger } from "../../Common/dataAccess/createTrigger";
import { updateTrigger } from "../../Common/dataAccess/updateTrigger";
import * as ViewModels from "../../Contracts/ViewModels";
import { Keys } from "../../Localization/Keys.generated";
import { t } from "../../Localization/t";
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { SqlTriggerResource } from "../../Utils/arm/generatedClients/cosmos/types";
@@ -21,8 +19,8 @@ import { EditorReact } from "../Controls/Editor/EditorReact";
import { useCommandBar } from "../Menus/CommandBar/CommandBarComponentAdapter";
import TriggerTab from "./TriggerTab";
const triggerTypeOptions: IDropdownOption[] = [
{ key: "Pre", text: t(Keys.tabs.trigger.pre) },
{ key: "Post", text: t(Keys.tabs.trigger.post) },
{ key: "Pre", text: "Pre" },
{ key: "Post", text: "Post" },
];
const dropdownStyles: Partial<IDropdownStyles> = {
@@ -149,10 +147,10 @@ const dropdownStyles: Partial<IDropdownStyles> = {
};
const triggerOperationOptions: IDropdownOption[] = [
{ key: "All", text: t(Keys.tabs.trigger.all) },
{ key: "Create", text: t(Keys.tabs.trigger.operationCreate) },
{ key: "Delete", text: t(Keys.tabs.trigger.operationDelete) },
{ key: "Replace", text: t(Keys.tabs.trigger.operationReplace) },
{ key: "All", text: "All" },
{ key: "Create", text: "Create" },
{ key: "Delete", text: "Delete" },
{ key: "Replace", text: "Replace" },
];
interface Ibutton {
@@ -336,7 +334,7 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: CommandButtonComponentProps[] = [];
const label = t(Keys.common.save);
const label = "Save";
if (this.saveButton.visible) {
buttons.push({
setState: this.setState,
@@ -353,7 +351,7 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
}
if (this.updateButton.visible) {
const label = t(Keys.common.update);
const label = "Update";
buttons.push({
...this,
iconSrc: SaveIcon,
@@ -368,7 +366,7 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
}
if (this.discardButton.visible) {
const label = t(Keys.common.discard);
const label = "Discard";
buttons.push({
setState: this.setState,
...this,
@@ -417,14 +415,14 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
<div className="tab-pane flexContainer trigger-form" role="tabpanel">
<TextField
className="trigger-field"
label={t(Keys.tabs.trigger.id)}
label="Trigger Id"
id="entityTimeId"
autoFocus
required
type="text"
pattern={ValidCosmosDbIdInputPattern.source}
title={ValidCosmosDbIdDescription}
placeholder={t(Keys.tabs.trigger.idPlaceholder)}
placeholder="Enter the new trigger id"
size={40}
value={triggerId}
readOnly={!isIdEditable}
@@ -448,8 +446,8 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
}}
/>
<Dropdown
placeholder={t(Keys.tabs.trigger.type)}
label={t(Keys.tabs.trigger.type)}
placeholder="Trigger Type"
label="Trigger Type"
options={triggerTypeOptions}
selectedKey={triggerType}
className="trigger-field"
@@ -457,8 +455,8 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
styles={dropdownStyles}
/>
<Dropdown
placeholder={t(Keys.tabs.trigger.operation)}
label={t(Keys.tabs.trigger.operation)}
placeholder="Trigger Operation"
label="Trigger Operation"
selectedKey={triggerOperation}
options={triggerOperationOptions}
className="trigger-field"
@@ -467,12 +465,12 @@ export class TriggerTabContent extends Component<TriggerTab, ITriggerTabContentS
}
styles={dropdownStyles}
/>
<Label className="trigger-field">{t(Keys.tabs.trigger.body)}</Label>
<Label className="trigger-field">Trigger Body</Label>
<EditorReact
language={"json"}
content={triggerBody}
isReadOnly={false}
ariaLabel={t(Keys.tabs.trigger.bodyAriaLabel)}
ariaLabel={"Graph JSON"}
onContentChanged={this.handleTriggerBodyChange}
/>
</div>

View File

@@ -12,8 +12,6 @@ import { getErrorMessage, getErrorStack } from "../../Common/ErrorHandlingUtils"
import { createUserDefinedFunction } from "../../Common/dataAccess/createUserDefinedFunction";
import { updateUserDefinedFunction } from "../../Common/dataAccess/updateUserDefinedFunction";
import * as ViewModels from "../../Contracts/ViewModels";
import { Keys } from "../../Localization/Keys.generated";
import { t } from "../../Localization/t";
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { CommandButtonComponentProps } from "../Controls/CommandButton/CommandButtonComponent";
@@ -84,7 +82,7 @@ export default class UserDefinedFunctionTabContent extends Component<
protected getTabsButtons(): CommandButtonComponentProps[] {
const buttons: CommandButtonComponentProps[] = [];
const label = t(Keys.common.save);
const label = "Save";
if (this.saveButton.visible) {
buttons.push({
...this,
@@ -101,7 +99,7 @@ export default class UserDefinedFunctionTabContent extends Component<
}
if (this.updateButton.visible) {
const label = t(Keys.common.update);
const label = "Update";
buttons.push({
...this,
iconSrc: SaveIcon,
@@ -116,7 +114,7 @@ export default class UserDefinedFunctionTabContent extends Component<
}
if (this.discardButton.visible) {
const label = t(Keys.common.discard);
const label = "Discard";
buttons.push({
setState: this.setState,
...this,
@@ -267,7 +265,7 @@ export default class UserDefinedFunctionTabContent extends Component<
<FluentProvider theme={currentTheme}>
<TextField
className="trigger-field"
label={t(Keys.tabs.udf.id)}
label="User Defined Function Id"
id="entityTimeId"
autoFocus
required
@@ -275,7 +273,7 @@ export default class UserDefinedFunctionTabContent extends Component<
type="text"
pattern={ValidCosmosDbIdInputPattern.source}
title={ValidCosmosDbIdDescription}
placeholder={t(Keys.tabs.udf.idPlaceholder)}
placeholder="Enter the new user defined function id"
size={40}
value={udfId}
onChange={this.handleUdfIdChange}
@@ -301,12 +299,12 @@ export default class UserDefinedFunctionTabContent extends Component<
}}
/>{" "}
</FluentProvider>
<Label className="trigger-field">{t(Keys.tabs.udf.body)}</Label>
<Label className="trigger-field">User Defined Function Body</Label>
<EditorReact
language={"javascript"}
content={udfBody}
isReadOnly={false}
ariaLabel={t(Keys.tabs.udf.bodyAriaLabel)}
ariaLabel={"User defined function body"}
onContentChanged={this.handleUdfBodyChange}
/>
</div>

View File

@@ -141,6 +141,7 @@ export default class Collection implements ViewModels.Collection {
const defaultDataMaskingPolicy: DataModels.DataMaskingPolicy = {
includedPaths: Array<{ path: string; strategy: string; startPosition: number; length: number }>(),
excludedPaths: Array<string>(),
isPolicyEnabled: true,
};
const observablePolicy = ko.observable(data.dataMaskingPolicy || defaultDataMaskingPolicy);
observablePolicy.subscribe(() => {});

View File

@@ -1,4 +1,3 @@
import "./i18n";
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Arrow from "../images/Arrow.svg";

View File

@@ -1,14 +0,0 @@
{
"Projects": [
{
"LanguageSet": "Azure_LanguagesExt",
"LocItems": [
{
"SourceFile": "src\\Localization\\en\\Resources.json",
"CopyOption": "LangIDOnPath",
"OutputPath": "src\\Localization"
}
]
}
]
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Zrušit",
"close": "Zavřít",
"save": "Uložit",
"delete": "Odstranit",
"update": "Aktualizovat",
"discard": "Zahodit",
"execute": "Execute",
"loading": "Načítání",
"loadingEllipsis": "Načítání…",
"next": "Další",
"previous": "Předchozí",
"yes": "Ano",
"no": "Ne",
"result": "Výsledek",
"learnMore": "Další informace",
"getStarted": "Začínáme",
"retry": "Zkusit znovu",
"apply": "Použít",
"refresh": "Aktualizovat",
"copy": "Kopírovat",
"create": "Vytvořit",
"confirm": "Potvrdit",
"open": "Otevřít",
"rename": "Přejmenovat",
"download": "Stáhnout",
"upload": "Nahrát",
"connect": "Připojit",
"remove": "Odebrat",
"increaseValueBy1": "Zvýšit hodnotu o 1",
"decreaseValueBy1": "Snížit hodnotu o 1"
},
"splashScreen": {
"title": {
"default": "Vítá vás Azure Cosmos DB",
"postgres": "Vítá vás Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Vítá vás Azure DocumentDB (s kompatibilitou MongoDB)"
},
"subtitle": {
"default": "Globálně distribuovaná databázová služba s více modely pro libovolné škálování",
"getStarted": "Začněte s našimi ukázkovými datovými sadami, dokumentací a dalšími nástroji."
},
"quickStart": {
"title": "Launch quick start",
"description": "Launch a quick start tutorial to get started with sample data"
},
"newCollection": {
"title": "New {{collectionName}}",
"description": "Create a new container for storage and throughput"
},
"samplesGallery": {
"title": "Azure Cosmos DB Samples Gallery",
"description": "Discover samples that showcase scalable, intelligent app patterns. Try one now to see how fast you can go from concept to code with Cosmos DB"
},
"connectCard": {
"title": "Connect",
"description": "Prefer using your own choice of tooling? Find the connection string you need to connect",
"pgAdmin": {
"title": "Connect with pgAdmin",
"description": "Prefer pgAdmin? Find your connection strings here"
},
"vsCode": {
"title": "Připojení pomocí VS Code",
"description": "Query and Manage your MongoDB and DocumentDB clusters in Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Create table and interact with data using PostgreSQL's shell interface"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Create a collection and interact with data using MongoDB's shell interface"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "New to Cosmos DB PGSQL?",
"body": "Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you can find sample data, query."
},
"resetPassword": {
"headline": "Create your password",
"body": "If you haven't changed your password yet, change it now."
},
"coachMark": {
"headline": "Start with sample {{collectionName}}",
"body": "You will be guided to create a sample container with sample data, then we will give you a tour of data explorer. You can also cancel launching this tour and explore yourself"
}
},
"sections": {
"recents": "Recents",
"clearRecents": "Clear Recents",
"top3": "Top 3 things you need to know",
"learningResources": "Learning Resources",
"nextSteps": "Next steps",
"tipsAndLearnMore": "Tips & learn more",
"notebook": "Notebook",
"needHelp": "Need help?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Advanced Modeling Patterns",
"description": "Learn advanced strategies to optimize your database."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn to apply data model and partitioning strategies."
},
"resourcePlanning": {
"title": "Plan Your Resource Requirements",
"description": "Get to know the different configuration choices."
}
},
"mongo": {
"whatIsMongo": {
"title": "What is the MongoDB API?",
"description": "Understand Azure Cosmos DB for MongoDB and its features."
},
"features": {
"title": "Features and Syntax",
"description": "Discover the advantages and features"
},
"migrate": {
"title": "Migrate Your Data",
"description": "Pre-migration steps for moving data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Build a Java App",
"description": "Create a Java app using an SDK."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works."
},
"requestUnits": {
"title": "Request Units (RUs)",
"description": "Understand RU charges."
}
},
"gremlin": {
"dataModeling": {
"title": "Data Modeling",
"description": "Graph data modeling recommendations"
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works"
},
"queryData": {
"title": "Query Data",
"description": "Querying data with Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "What is the Table API?",
"description": "Understand Azure Cosmos DB for Table and its features"
},
"migrate": {
"title": "Migrate your data",
"description": "Learn how to migrate your data"
},
"faq": {
"title": "Azure Cosmos DB for Table FAQs",
"description": "Common questions about Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Data Explorer keyboard shortcuts",
"description": "Learn keyboard shortcuts to navigate Data Explorer."
},
"liveTv": {
"title": "Learn the Fundamentals",
"description": "Watch Azure Cosmos DB Live TV show introductory and how to videos."
},
"sql": {
"sdk": {
"title": "Get Started using an SDK",
"description": "Learn about the Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrate Your Data",
"description": "Migrate data using Azure services and open-source solutions."
}
},
"mongo": {
"nodejs": {
"title": "Build an app with Node.js",
"description": "Create a Node.js app."
},
"gettingStarted": {
"title": "Getting Started Guide",
"description": "Learn the basics to get started."
}
},
"cassandra": {
"createContainer": {
"title": "Create a Container",
"description": "Get to know the create a container options."
},
"throughput": {
"title": "Provision Throughput",
"description": "Learn how to configure throughput."
}
},
"gremlin": {
"getStarted": {
"title": "Get Started ",
"description": "Create, query, and traverse using the Gremlin console"
},
"importData": {
"title": "Import Graph Data",
"description": "Learn Bulk ingestion data using BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Build a .NET App",
"description": "How to access Azure Cosmos DB for Table from a .NET app."
},
"java": {
"title": "Build a Java App",
"description": "Create a Azure Cosmos DB for Table app with Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Data Modeling",
"distributionColumn": "How to choose a Distribution Column",
"buildApps": "Build Apps with Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrate Data",
"vectorSearch": "Build AI apps with Vector Search",
"buildApps": "Build Apps with Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Performance Tuning",
"diagnosticQueries": "Useful Diagnostic Queries",
"sqlReference": "Distributed SQL Reference"
},
"vcoreMongo": {
"vectorSearch": "Vector Search",
"textIndexing": "Text Indexing",
"troubleshoot": "Troubleshoot common issues"
}
},
"fabric": {
"buildTitle": "Build your database",
"useTitle": "Use your database",
"newContainer": {
"title": "New container",
"description": "Create a destination container to store your data"
},
"sampleData": {
"title": "Sample Data",
"description": "Load sample data in your database"
},
"sampleVectorData": {
"title": "Sample Vector Data",
"description": "Load sample vector data with text-embedding-ada-002"
},
"appDevelopment": {
"title": "App development",
"description": "Start here to use an SDK to build your apps"
},
"sampleGallery": {
"title": "Sample Gallery",
"description": "Get real-world end-to-end samples"
}
},
"sampleDataDialog": {
"title": "Sample Data",
"startButton": "Start",
"createPrompt": "Create a container \"{{containerName}}\" and import sample data into it. This may take a few minutes.",
"creatingContainer": "Creating container \"{{containerName}}\"...",
"importingData": "Importing data into \"{{containerName}}\"...",
"success": "Successfully created \"{{containerName}}\" with sample data.",
"errorContainerExists": "The container \"{{containerName}}\" in database \"{{databaseName}}\" already exists. Please delete it and retry.",
"errorCreateContainer": "Failed to create container: {{error}}",
"errorImportData": "Failed to import data: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Abbrechen",
"close": "Schließen",
"save": "Speichern",
"delete": "Löschen",
"update": "Aktualisieren",
"discard": "Verwerfen",
"execute": "Ausführen",
"loading": "Wird geladen",
"loadingEllipsis": "Wird geladen...",
"next": "Weiter",
"previous": "Zurück",
"yes": "Ja",
"no": "Nein",
"result": "Ergebnis",
"learnMore": "Weitere Informationen",
"getStarted": "Erste Schritte",
"retry": "Wiederholen",
"apply": "Anwenden",
"refresh": "Aktualisieren",
"copy": "Kopieren",
"create": "Erstellen",
"confirm": "Bestätigen",
"open": "Öffnen",
"rename": "Umbenennen",
"download": "Herunterladen",
"upload": "Hochladen",
"connect": "Verbinden",
"remove": "Entfernen",
"increaseValueBy1": "Wert um 1 erhöhen",
"decreaseValueBy1": "Wert um 1 verringern"
},
"splashScreen": {
"title": {
"default": "Willkommen bei Azure Cosmos DB",
"postgres": "Willkommen bei Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Willkommen bei Azure DocumentDB (mit MongoDB-Kompatibilität)"
},
"subtitle": {
"default": "Global verteilter Datenbankdienst mit Unterstützung mehrerer Datenmodelle in jeder Größenordnung",
"getStarted": "Erste Schritte mit unseren Beispieldatensätzen, der Dokumentation und weiteren Tools."
},
"quickStart": {
"title": "Schnellstart starten",
"description": "Starten Sie ein Schnellstarttutorial, um mit Beispieldaten zu beginnen."
},
"newCollection": {
"title": "Neue {{collectionName}}",
"description": "Neuen Container für Speicher und Durchsatz erstellen"
},
"samplesGallery": {
"title": "Azure Cosmos DB-Beispielgalerie",
"description": "Entdecken Sie Beispiele, die skalierbare, intelligente App-Muster zeigen. Probieren Sie jetzt eines aus, um zu sehen, wie schnell Sie mit Cosmos DB vom Konzept zum Code gelangen."
},
"connectCard": {
"title": "Verbinden",
"description": "Bevorzugen Sie Ihre eigene Toolauswahl? Finden Sie die Verbindungszeichenfolge, die Sie für die Verbindung benötigen.",
"pgAdmin": {
"title": "Verbindung mit pgAdmin herstellen",
"description": "pgAdmin bevorzugen? Hier finden Sie Ihre Verbindungszeichenfolgen."
},
"vsCode": {
"title": "Mit VS Code verbinden",
"description": "Abfragen und Verwalten Ihrer MongoDB- und DocumentDB-Cluster in Visual Studio Code."
}
},
"shell": {
"postgres": {
"title": "PostgreSQL-Shell",
"description": "Erstellen Sie eine Tabelle und interagieren Sie mit Daten über die Shellschnittstelle von PostgreSQL."
},
"vcoreMongo": {
"title": "Mongo-Shell",
"description": "Erstellen Sie eine Sammlung und interagieren Sie mit Daten über die Shellschnittstelle von MongoDB."
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "Neu bei Cosmos DB PGSQL?",
"body": "Willkommen! Wenn Sie neu bei Cosmos DB PGSQL sind und Hilfe beim Einstieg benötigen, finden Sie hier Beispieldaten und Abfragen."
},
"resetPassword": {
"headline": "Ihr Kennwort erstellen",
"body": "Wenn Sie Ihr Kennwort noch nicht geändert haben, ändern Sie es jetzt."
},
"coachMark": {
"headline": "Mit Beispiel „{{collectionName}}“ starten",
"body": "Sie werden angeleitet, einen Beispielcontainer mit Beispieldaten zu erstellen. Anschließend erhalten Sie eine Tour durch den Datenexplorer. Sie können die Tour auch abbrechen und selbst erkunden."
}
},
"sections": {
"recents": "Zuletzt verwendet",
"clearRecents": "Zuletzt verwendete Elemente löschen",
"top3": "Die drei wichtigsten Dinge, die Sie wissen sollten",
"learningResources": "Lernressourcen",
"nextSteps": "Nächste Schritte",
"tipsAndLearnMore": "Tipps und weitere Informationen",
"notebook": "Notebook",
"needHelp": "Benötigen Sie Hilfe?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Erweiterte Modellierungsmuster",
"description": "Erfahren Sie mehr über fortgeschrittene Strategien zur Optimierung Ihrer Datenbank."
},
"partitioning": {
"title": "Best Practices für die Partitionierung",
"description": "Lernen Sie, Datenmodell- und Partitionierungsstrategien anzuwenden."
},
"resourcePlanning": {
"title": "Ihre Ressourcenanforderungen planen",
"description": "Machen Sie sich mit den verschiedenen Konfigurationsmöglichkeiten vertraut."
}
},
"mongo": {
"whatIsMongo": {
"title": "Was ist die MongoDB-API?",
"description": "Verstehen Sie Azure Cosmos DB for MongoDB und seine Funktionen."
},
"features": {
"title": "Funktionen und Syntax",
"description": "Entdecken Sie die Vorteile und Funktionen"
},
"migrate": {
"title": "Ihre Daten migrieren",
"description": "Vorbereitende Schritte zur Datenmigration"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Java-App erstellen",
"description": "Java-App mithilfe eines SDK erstellen."
},
"partitioning": {
"title": "Best Practices für die Partitionierung",
"description": "Erfahren Sie, wie Partitionierung funktioniert."
},
"requestUnits": {
"title": "Anforderungseinheiten (RUs)",
"description": "RU-Gebühren verstehen"
}
},
"gremlin": {
"dataModeling": {
"title": "Datenmodellierung",
"description": "Empfehlungen zur Graphdatenmodellierung"
},
"partitioning": {
"title": "Best Practices für die Partitionierung",
"description": "Erfahren Sie, wie Partitionierung funktioniert"
},
"queryData": {
"title": "Daten abfragen",
"description": "Daten mit Gremlin abfragen"
}
},
"tables": {
"whatIsTable": {
"title": "Was ist die Table-API?",
"description": "Verstehen Sie Azure Cosmos DB for Table und seine Funktionen."
},
"migrate": {
"title": "Ihre Daten migrieren",
"description": "Erfahren Sie, wie Sie Ihre Daten migrieren."
},
"faq": {
"title": "Häufig gestellte Fragen zu Azure Cosmos DB for Table",
"description": "Häufige Fragen zu Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Tastenkombinationen im Datenexplorer",
"description": "Lernen Sie Tastenkombinationen zur Navigation im Datenexplorer."
},
"liveTv": {
"title": "Grundlagen erlernen",
"description": "Sehen Sie sich die Einführung und Anleitungsvideos der Azure Cosmos DB Live TV-Sendung an."
},
"sql": {
"sdk": {
"title": "Erste Schritte mit einem SDK",
"description": "Mehr über das Azure Cosmos DB SDK erfahren."
},
"migrate": {
"title": "Ihre Daten migrieren",
"description": "Migrieren Sie Daten mit Azure-Diensten und Open-Source-Lösungen."
}
},
"mongo": {
"nodejs": {
"title": "App mit Node.js erstellen",
"description": "Node.js-App erstellen."
},
"gettingStarted": {
"title": "Leitfaden für erste Schritte",
"description": "Lernen Sie die Grundlagen für den Einstieg kennen."
}
},
"cassandra": {
"createContainer": {
"title": "Container erstellen",
"description": "Erfahren Sie mehr über die Optionen zum Erstellen eines Containers."
},
"throughput": {
"title": "Durchsatz bereitstellen",
"description": "Erfahren Sie, wie Sie den Durchsatz konfigurieren."
}
},
"gremlin": {
"getStarted": {
"title": "Erste Schritte ",
"description": "Erstellen, Abfragen und Durchlaufen mithilfe der Gremlin-Konsole"
},
"importData": {
"title": "Graphdaten importieren",
"description": "Massendatenaufnahme mit BulkExecutor erlernen"
}
},
"tables": {
"dotnet": {
"title": ".NET-App erstellen",
"description": "So greifen Sie mit einer .NET-App auf Azure Cosmos DB for Table zu."
},
"java": {
"title": "Java-App erstellen",
"description": "Erstellen Sie eine Azure Cosmos DB for Table-App mit dem Java SDK. "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Datenmodellierung",
"distributionColumn": "So wählen Sie eine Verteilungsspalte aus.",
"buildApps": "Apps mit Python/Java/Django erstellen"
},
"vcoreMongo": {
"migrateData": "Daten migrieren",
"vectorSearch": "KI-Apps mit Vektorsuche erstellen",
"buildApps": "Apps mit Node.js erstellen"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Leistungsoptimierung",
"diagnosticQueries": "Nützliche Diagnoseabfragen",
"sqlReference": "Referenz für verteiltes SQL"
},
"vcoreMongo": {
"vectorSearch": "Vektorsuche",
"textIndexing": "Textindizierung",
"troubleshoot": "Häufige Probleme beheben"
}
},
"fabric": {
"buildTitle": "Ihre Datenbank erstellen",
"useTitle": "Ihre Datenbank nutzen",
"newContainer": {
"title": "Neuer Container",
"description": "Zielcontainer zum Speichern Ihrer Daten erstellen."
},
"sampleData": {
"title": "Beispieldaten",
"description": "Beispieldaten in Ihrer Datenbank laden"
},
"sampleVectorData": {
"title": "Beispielvektordaten",
"description": "Beispielvektordaten mit text-embedding-ada-002 laden"
},
"appDevelopment": {
"title": "App-Entwicklung",
"description": "Starten Sie hier, um ein SDK zum Erstellen Ihrer Apps zu verwenden."
},
"sampleGallery": {
"title": "Beispielgalerie",
"description": "End-to-End-Beispiele aus der Praxis ansehen"
}
},
"sampleDataDialog": {
"title": "Beispieldaten",
"startButton": "Starten",
"createPrompt": "Erstellen Sie einen Container „{{containerName}}“ und importieren Sie Beispieldaten. Dies kann einige Minuten dauern.",
"creatingContainer": "Container „{{containerName}}“ wird erstellt...",
"importingData": "Daten werden in „{{containerName}}“ importiert...",
"success": "„{{containerName}}“ wurde erfolgreich mit Beispieldaten erstellt.",
"errorContainerExists": "Der Container „{{containerName}}“ in der Datenbank „{{databaseName}}“ existiert bereits. Bitte löschen Sie ihn und versuchen Sie es erneut.",
"errorCreateContainer": "Fehler beim Erstellen des Containers: {{error}}",
"errorImportData": "Fehler beim Importieren von Daten: {{error}}"
}
}
}

View File

@@ -1,416 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Cancel",
"close": "Close",
"save": "Save",
"delete": "Delete",
"update": "Update",
"discard": "Discard",
"execute": "Execute",
"loading": "Loading",
"loadingEllipsis": "Loading...",
"next": "Next",
"previous": "Previous",
"yes": "Yes",
"no": "No",
"result": "Result",
"learnMore": "Learn more",
"getStarted": "Get started",
"retry": "Retry",
"apply": "Apply",
"refresh": "Refresh",
"copy": "Copy",
"create": "Create",
"confirm": "Confirm",
"open": "Open",
"rename": "Rename",
"download": "Download",
"upload": "Upload",
"connect": "Connect",
"remove": "Remove",
"increaseValueBy1": "Increase value by 1",
"decreaseValueBy1": "Decrease value by 1"
},
"splashScreen": {
"title": {
"default": "Welcome to Azure Cosmos DB",
"postgres": "Welcome to Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Welcome to Azure DocumentDB (with MongoDB compatibility)"
},
"subtitle": {
"default": "Globally distributed, multi-model database service for any scale",
"getStarted": "Get started with our sample datasets, documentation, and additional tools."
},
"quickStart": {
"title": "Launch quick start",
"description": "Launch a quick start tutorial to get started with sample data"
},
"newCollection": {
"title": "New {{collectionName}}",
"description": "Create a new container for storage and throughput"
},
"samplesGallery": {
"title": "Azure Cosmos DB Samples Gallery",
"description": "Discover samples that showcase scalable, intelligent app patterns. Try one now to see how fast you can go from concept to code with Cosmos DB"
},
"connectCard": {
"title": "Connect",
"description": "Prefer using your own choice of tooling? Find the connection string you need to connect",
"pgAdmin": {
"title": "Connect with pgAdmin",
"description": "Prefer pgAdmin? Find your connection strings here"
},
"vsCode": {
"title": "Connect with VS Code",
"description": "Query and Manage your MongoDB and DocumentDB clusters in Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Create table and interact with data using PostgreSQL's shell interface"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Create a collection and interact with data using MongoDB's shell interface"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "New to Cosmos DB PGSQL?",
"body": "Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you can find sample data, query."
},
"resetPassword": {
"headline": "Create your password",
"body": "If you haven't changed your password yet, change it now."
},
"coachMark": {
"headline": "Start with sample {{collectionName}}",
"body": "You will be guided to create a sample container with sample data, then we will give you a tour of data explorer. You can also cancel launching this tour and explore yourself"
}
},
"sections": {
"recents": "Recents",
"clearRecents": "Clear Recents",
"top3": "Top 3 things you need to know",
"learningResources": "Learning Resources",
"nextSteps": "Next steps",
"tipsAndLearnMore": "Tips & learn more",
"notebook": "Notebook",
"needHelp": "Need help?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Advanced Modeling Patterns",
"description": "Learn advanced strategies to optimize your database."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn to apply data model and partitioning strategies."
},
"resourcePlanning": {
"title": "Plan Your Resource Requirements",
"description": "Get to know the different configuration choices."
}
},
"mongo": {
"whatIsMongo": {
"title": "What is the MongoDB API?",
"description": "Understand Azure Cosmos DB for MongoDB and its features."
},
"features": {
"title": "Features and Syntax",
"description": "Discover the advantages and features"
},
"migrate": {
"title": "Migrate Your Data",
"description": "Pre-migration steps for moving data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Build a Java App",
"description": "Create a Java app using an SDK."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works."
},
"requestUnits": {
"title": "Request Units (RUs)",
"description": "Understand RU charges."
}
},
"gremlin": {
"dataModeling": {
"title": "Data Modeling",
"description": "Graph data modeling recommendations"
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works"
},
"queryData": {
"title": "Query Data",
"description": "Querying data with Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "What is the Table API?",
"description": "Understand Azure Cosmos DB for Table and its features"
},
"migrate": {
"title": "Migrate your data",
"description": "Learn how to migrate your data"
},
"faq": {
"title": "Azure Cosmos DB for Table FAQs",
"description": "Common questions about Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Data Explorer keyboard shortcuts",
"description": "Learn keyboard shortcuts to navigate Data Explorer."
},
"liveTv": {
"title": "Learn the Fundamentals",
"description": "Watch Azure Cosmos DB Live TV show introductory and how to videos."
},
"sql": {
"sdk": {
"title": "Get Started using an SDK",
"description": "Learn about the Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrate Your Data",
"description": "Migrate data using Azure services and open-source solutions."
}
},
"mongo": {
"nodejs": {
"title": "Build an app with Node.js",
"description": "Create a Node.js app."
},
"gettingStarted": {
"title": "Getting Started Guide",
"description": "Learn the basics to get started."
}
},
"cassandra": {
"createContainer": {
"title": "Create a Container",
"description": "Get to know the create a container options."
},
"throughput": {
"title": "Provision Throughput",
"description": "Learn how to configure throughput."
}
},
"gremlin": {
"getStarted": {
"title": "Get Started ",
"description": "Create, query, and traverse using the Gremlin console"
},
"importData": {
"title": "Import Graph Data",
"description": "Learn Bulk ingestion data using BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Build a .NET App",
"description": "How to access Azure Cosmos DB for Table from a .NET app."
},
"java": {
"title": "Build a Java App",
"description": "Create a Azure Cosmos DB for Table app with Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Data Modeling",
"distributionColumn": "How to choose a Distribution Column",
"buildApps": "Build Apps with Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrate Data",
"vectorSearch": "Build AI apps with Vector Search",
"buildApps": "Build Apps with Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Performance Tuning",
"diagnosticQueries": "Useful Diagnostic Queries",
"sqlReference": "Distributed SQL Reference"
},
"vcoreMongo": {
"vectorSearch": "Vector Search",
"textIndexing": "Text Indexing",
"troubleshoot": "Troubleshoot common issues"
}
},
"fabric": {
"buildTitle": "Build your database",
"useTitle": "Use your database",
"newContainer": {
"title": "New container",
"description": "Create a destination container to store your data"
},
"sampleData": {
"title": "Sample Data",
"description": "Load sample data in your database"
},
"sampleVectorData": {
"title": "Sample Vector Data",
"description": "Load sample vector data with text-embedding-ada-002"
},
"appDevelopment": {
"title": "App development",
"description": "Start here to use an SDK to build your apps"
},
"sampleGallery": {
"title": "Sample Gallery",
"description": "Get real-world end-to-end samples"
}
},
"sampleDataDialog": {
"title": "Sample Data",
"startButton": "Start",
"createPrompt": "Create a container \"{{containerName}}\" and import sample data into it. This may take a few minutes.",
"creatingContainer": "Creating container \"{{containerName}}\"...",
"importingData": "Importing data into \"{{containerName}}\"...",
"success": "Successfully created \"{{containerName}}\" with sample data.",
"errorContainerExists": "The container \"{{containerName}}\" in database \"{{databaseName}}\" already exists. Please delete it and retry.",
"errorCreateContainer": "Failed to create container: {{error}}",
"errorImportData": "Failed to import data: {{error}}"
}
},
"contextMenu": {
"newContainer": "New {{containerName}}",
"restoreContainer": "Restore {{containerName}}",
"deleteDatabase": "Delete {{databaseName}}",
"deleteContainer": "Delete {{containerName}}",
"newSqlQuery": "New SQL Query",
"newQuery": "New Query",
"openMongoShell": "Open Mongo Shell",
"newShell": "New Shell",
"openCassandraShell": "Open Cassandra Shell",
"newStoredProcedure": "New Stored Procedure",
"newUdf": "New UDF",
"newTrigger": "New Trigger",
"deleteStoredProcedure": "Delete Stored Procedure",
"deleteTrigger": "Delete Trigger",
"deleteUdf": "Delete User Defined Function"
},
"tabs": {
"documents": {
"newItem": "New Item",
"newDocument": "New Document",
"uploadItem": "Upload Item",
"applyFilter": "Apply Filter",
"unsavedChanges": "Unsaved changes",
"unsavedChangesMessage": "Your unsaved changes will be lost. Do you want to continue?",
"createDocumentFailed": "Create document failed",
"updateDocumentFailed": "Update document failed",
"documentDeleted": "Document successfully deleted.",
"deleteDocumentDialogTitle": "Delete document",
"deleteDocumentsDialogTitle": "Delete documents",
"throttlingError": "Some documents failed to delete due to a rate limiting error. Please try again later. To prevent this in the future, consider increasing the throughput on your container or database.",
"deleteFailed": "Deleting document(s) failed ({{error}})",
"missingShardProperty": "The document is lacking the shard property: {{partitionKeyProperty}}",
"refreshGridFailed": "Refresh documents grid failed",
"confirmDelete": "Are you sure you want to delete {{documentName}}?",
"confirmDeleteTitle": "Confirm delete",
"selectedItems": "the selected {{count}} items",
"selectedItem": "the selected item",
"selectedDocuments": "the selected {{count}} documents",
"selectedDocument": "the selected document",
"deleteDocumentFailedLog": "Failed to delete document {{documentId}} with status code {{statusCode}}",
"deleteSuccessLog": "Successfully deleted {{count}} document(s)",
"deleteThrottledLog": "Failed to delete {{count}} document(s) due to \"Request too large\" (429) error. Retrying...",
"missingShardKeyLog": "Failed to save new document: Document shard key not defined",
"filterTooltip": "Type a query predicate or choose one from the list.",
"loadMore": "Load more",
"documentEditor": "Document editor",
"savedFilters": "Saved filters",
"defaultFilters": "Default filters",
"abort": "Abort",
"deletingDocuments": "Deleting {{count}} document(s)",
"deletedDocumentsSuccess": "Successfully deleted {{count}} document(s).",
"deleteAborted": "Deleting document(s) was aborted.",
"failedToDeleteDocuments": "Failed to delete {{count}} document(s).",
"requestTooLargeBase": "Some delete requests failed due to a \"Request too large\" exception (429)",
"retriedSuccessfully": "but were successfully retried.",
"retryingNow": "Retrying now.",
"increaseThroughputTip": "To prevent this in the future, consider increasing the throughput on your container or database.",
"numberOfSelectedDocuments": "Number of selected documents: {{count}}",
"mongoFilterPlaceholder": "Type a query predicate (e.g., {\"id\":\"foo\"}), or choose one from the drop down list, or leave empty to query all documents.",
"sqlFilterPlaceholder": "Type a query predicate (e.g., WHERE c.id=\"1\"), or choose one from the drop down list, or leave empty to query all documents.",
"error": "Error",
"warning": "Warning"
},
"query": {
"executeQuery": "Execute Query",
"executeSelection": "Execute Selection",
"saveQuery": "Save Query",
"downloadQuery": "Download Query",
"cancelQuery": "Cancel query",
"openSavedQueries": "Open Saved Queries",
"vertical": "Vertical",
"horizontal": "Horizontal",
"view": "View",
"editingQuery": "Editing Query"
},
"storedProcedure": {
"id": "Stored Procedure Id",
"idPlaceholder": "Enter the new stored procedure id",
"idAriaLabel": "Stored procedure id",
"body": "Stored Procedure Body",
"bodyAriaLabel": "Stored procedure body",
"successfulExecution": "Successful execution of stored procedure",
"resultAriaLabel": "Execute stored procedure result",
"logsAriaLabel": "Execute stored procedure logs",
"errors": "Errors:",
"errorDetailsAriaLabel": "Error details link",
"moreDetails": "More details",
"consoleLogTab": "console.log"
},
"trigger": {
"id": "Trigger Id",
"idPlaceholder": "Enter the new trigger id",
"type": "Trigger Type",
"operation": "Trigger Operation",
"body": "Trigger Body",
"bodyAriaLabel": "Trigger body",
"pre": "Pre",
"post": "Post",
"all": "All",
"operationCreate": "Create",
"operationDelete": "Delete",
"operationReplace": "Replace"
},
"udf": {
"id": "User Defined Function Id",
"idPlaceholder": "Enter the new user defined function id",
"body": "User Defined Function Body",
"bodyAriaLabel": "User defined function body"
},
"conflicts": {
"unsavedChanges": "Unsaved changes",
"changesWillBeLost": "Changes will be lost. Do you want to continue?",
"resolveConflictFailed": "Resolve conflict failed",
"deleteConflictFailed": "Delete conflict failed",
"refreshGridFailed": "Refresh documents grid failed"
},
"mongoShell": {
"title": "Mongo Shell"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "Aceptar",
"cancel": "Cancelar",
"close": "Cerrar",
"save": "Guardar",
"delete": "Eliminar",
"update": "Actualizar",
"discard": "Descartar",
"execute": "Ejecutar",
"loading": "Cargando",
"loadingEllipsis": "Cargando…",
"next": "Siguiente",
"previous": "Anterior",
"yes": "Sí",
"no": "No",
"result": "Resultado",
"learnMore": "Más información",
"getStarted": "Comenzar",
"retry": "Reintentar",
"apply": "Aplicar",
"refresh": "Actualizar",
"copy": "Copiar",
"create": "Crear",
"confirm": "Confirmar",
"open": "Abrir",
"rename": "Cambiar nombre",
"download": "Descargar",
"upload": "Cargar",
"connect": "Conectar",
"remove": "Quitar",
"increaseValueBy1": "Aumentar valor en 1",
"decreaseValueBy1": "Disminuir valor en 1"
},
"splashScreen": {
"title": {
"default": "Le presentamos Azure Cosmos DB",
"postgres": "Le damos la bienvenida a Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Le damos la bienvenida a Azure DocumentDB (con compatibilidad con MongoDB)"
},
"subtitle": {
"default": "Servicio de base de datos multimodelo distribuido globalmente para cualquier escala",
"getStarted": "Introducción a nuestros conjuntos de datos de ejemplo, documentación y herramientas adicionales."
},
"quickStart": {
"title": "Inicio rápido",
"description": "Iniciar un tutorial de inicio rápido para empezar a trabajar con datos de ejemplo"
},
"newCollection": {
"title": "Nuevo elemento: {{collectionName}}",
"description": "Creación de un nuevo contenedor para el almacenamiento y el rendimiento"
},
"samplesGallery": {
"title": "Galería de ejemplos de Azure Cosmos DB",
"description": "Descubra ejemplos que muestran patrones de aplicaciones inteligentes y escalables. Pruebe una ahora para ver la rapidez con la que puede pasar del concepto al código con Cosmos DB"
},
"connectCard": {
"title": "Conectar",
"description": "¿Prefiere usar sus propias herramientas? Busque la cadena de conexión que necesita para conectarse.",
"pgAdmin": {
"title": "Conexión con pgAdmin",
"description": "¿Prefiere pgAdmin? Busque las cadenas de conexión aquí"
},
"vsCode": {
"title": "Conectar con VS Code",
"description": "Consulta y administración de los clústeres de MongoDB y DocumentDB en Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Creación de una tabla e interacción con datos mediante la interfaz de shell de PostgreSQL"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Creación de una colección e interacción con datos mediante la interfaz de shell de MongoDB"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "¿Es nuevo en Cosmos DB PGSQL?",
"body": "Le damos la bienvenida Si no está familiarizado con Cosmos DB PGSQL y necesita ayuda para empezar, aquí puede encontrar datos de ejemplo y consultarlos."
},
"resetPassword": {
"headline": "Crear la contraseña",
"body": "Si aún no ha cambiado la contraseña, cámbiela ahora."
},
"coachMark": {
"headline": "Empezar con el ejemplo {{collectionName}}",
"body": "Se le guiará para crear un contenedor de ejemplo con datos de ejemplo y, a continuación, le ofreceremos un paseo por el explorador de datos. También puede cancelar la reserva de esta excursión y explorarla por su cuenta."
}
},
"sections": {
"recents": "Recientes",
"clearRecents": "Borrar recientes",
"top3": "3 cosas principales que debes saber",
"learningResources": "Recursos de aprendizaje",
"nextSteps": "Siguientes pasos",
"tipsAndLearnMore": "Sugerencias y más información",
"notebook": "Notebook",
"needHelp": "¿Necesita ayuda?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Patrones de modelado avanzados",
"description": "Obtenga información acerca de las estrategias avanzadas para optimizar la base de datos."
},
"partitioning": {
"title": "procedimientos recomendados de creación de particiones",
"description": "Aprenda a aplicar estrategias de creación de particiones y modelo de datos."
},
"resourcePlanning": {
"title": "Planear los requisitos de recursos",
"description": "Conozca las distintas opciones de configuración."
}
},
"mongo": {
"whatIsMongo": {
"title": "¿Qué es MongoDB API?",
"description": "Comprenda Azure Cosmos DB de MongoDB y sus características."
},
"features": {
"title": "Características y sintaxis",
"description": "Descubra las ventajas y características"
},
"migrate": {
"title": "Migrar los datos",
"description": "Pasos previos a la migración para mover datos"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Compilación de una aplicación java",
"description": "Cree una aplicación java mediante un SDK."
},
"partitioning": {
"title": "procedimientos recomendados de creación de particiones",
"description": "Obtenga información acerca de cómo funciona la creación de particiones."
},
"requestUnits": {
"title": "Unidades de solicitud (RU)",
"description": "Descripción de los cargos de RU."
}
},
"gremlin": {
"dataModeling": {
"title": "Modelado de datos",
"description": "Recomendaciones de modelado de datos de grafos"
},
"partitioning": {
"title": "procedimientos recomendados de creación de particiones",
"description": "Obtenga información sobre cómo funciona la creación de particiones"
},
"queryData": {
"title": "Consultar datos",
"description": "Consulta de datos con Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "¿Cuál es el Table API?",
"description": "Descripción de Azure Cosmos DB para Table y sus características"
},
"migrate": {
"title": "Migrar los datos",
"description": "Obtenga información sobre cómo migrar sus datos"
},
"faq": {
"title": "Azure Cosmos DB para preguntas más frecuentes sobre tablas",
"description": "Preguntas comunes sobre Azure Cosmos DB para table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Explorador de datos métodos abreviados de teclado",
"description": "Obtenga información acerca de los métodos abreviados de teclado para navegar por Explorador de datos."
},
"liveTv": {
"title": "Conozca los aspectos básicos",
"description": "Vea Azure Cosmos DB introducción a programas de TV en vivo y vídeos de procedimientos."
},
"sql": {
"sdk": {
"title": "Introducción al uso de un SDK",
"description": "Obtenga información acerca del SDK de Azure Cosmos DB."
},
"migrate": {
"title": "Migrar los datos",
"description": "Migre datos mediante servicios de Azure y soluciones de código abierto."
}
},
"mongo": {
"nodejs": {
"title": "Compilación de una aplicación con Node.js",
"description": "Cree una aplicación Node.js."
},
"gettingStarted": {
"title": "Guía de introducción",
"description": "Conozca los conceptos básicos para empezar."
}
},
"cassandra": {
"createContainer": {
"title": "Crear un contenedor",
"description": "Conozca las opciones de creación de un contenedor."
},
"throughput": {
"title": "Aprovisionar rendimiento",
"description": "Aprenda a configurar el rendimiento."
}
},
"gremlin": {
"getStarted": {
"title": "Introducción ",
"description": "Creación, consulta y recorrido mediante la consola de Gremlin"
},
"importData": {
"title": "Importar datos del gráfico",
"description": "Información sobre los datos de ingesta masiva mediante BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Compilación de una aplicación .NET",
"description": "Cómo acceder a Azure Cosmos DB para Table desde una aplicación .NET."
},
"java": {
"title": "Compilación de una aplicación java",
"description": "Creación de una Azure Cosmos DB para la aplicación Table con el SDK de Java "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Modelado de datos",
"distributionColumn": "Cómo elegir una columna de distribución",
"buildApps": "Compilación de aplicaciones con Python, Java y Django"
},
"vcoreMongo": {
"migrateData": "Migrar datos",
"vectorSearch": "Creación de aplicaciones de inteligencia artificial con Vector Search",
"buildApps": "Compilación de aplicaciones con Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Ajuste de rendimiento",
"diagnosticQueries": "Consultas de diagnóstico útiles",
"sqlReference": "Referencia de SQL distribuida"
},
"vcoreMongo": {
"vectorSearch": "Vector de búsqueda",
"textIndexing": "Indización de texto",
"troubleshoot": "Solucionar problemas comunes"
}
},
"fabric": {
"buildTitle": "Compilación de la base de datos",
"useTitle": "Uso de la base de datos",
"newContainer": {
"title": "Nuevo contenedor",
"description": "Creación de un contenedor de destino para almacenar los datos"
},
"sampleData": {
"title": "Datos de ejemplo",
"description": "Carga de datos de ejemplo en la base de datos"
},
"sampleVectorData": {
"title": "Datos vectoriales de ejemplo",
"description": "Carga de datos vectoriales de ejemplo con text-embedding-ada-002"
},
"appDevelopment": {
"title": "Desarrollo de aplicaciones",
"description": "Empiece aquí para usar un SDK para compilar sus aplicaciones"
},
"sampleGallery": {
"title": "Galería de ejemplos",
"description": "Obtener ejemplos de un extremo a otro del mundo real"
}
},
"sampleDataDialog": {
"title": "Datos de ejemplo",
"startButton": "Inicio",
"createPrompt": "Cree un contenedor \"{{containerName}}\" e importe datos de ejemplo en él. Esto podría tardar unos minutos.",
"creatingContainer": "Creando contenedor \"{{containerName}}\"...",
"importingData": "Importando datos en \"{{containerName}}\"...",
"success": "Se ha creado correctamente \"{{containerName}}\" con datos de ejemplo.",
"errorContainerExists": "El contenedor \"{{containerName}}\" de la base de datos \"{{databaseName}}\" ya existe. Elimínelo y vuelva a intentarlo.",
"errorCreateContainer": "Error al crear el contenedor: {{error}}",
"errorImportData": "No se pudieron importar los datos: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Annuler",
"close": "Fermer",
"save": "Enregistrer",
"delete": "Supprimer",
"update": "Mettre à jour",
"discard": "Abandonner",
"execute": "Exécuter",
"loading": "Chargement",
"loadingEllipsis": "Chargement en cours...",
"next": "Suivant",
"previous": "Précédent",
"yes": "Oui",
"no": "Non",
"result": "Résultat",
"learnMore": "En savoir plus",
"getStarted": "Démarrage",
"retry": "Réessayer",
"apply": "Appliquer",
"refresh": "Actualiser",
"copy": "Copier",
"create": "Créer",
"confirm": "Confirmer",
"open": "Ouvrir",
"rename": "Renommer",
"download": "Télécharger",
"upload": "Charger",
"connect": "Connexion",
"remove": "Supprimer",
"increaseValueBy1": "Augmenter la valeur de 1",
"decreaseValueBy1": "Diminuer la valeur de 1"
},
"splashScreen": {
"title": {
"default": "Bienvenue dans Azure Cosmos DB",
"postgres": "Bienvenue à Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Bienvenue à Azure DocumentDB (avec compatibilité MongoDB)"
},
"subtitle": {
"default": "Service de base de données multimodèle, mondialement distribuée et disponible à toute échelle",
"getStarted": "Commencez avec nos jeux de données dexemple, notre documentation et nos outils supplémentaires."
},
"quickStart": {
"title": "Lancer le démarrage rapide",
"description": "Lancer un didacticiel de démarrage rapide pour prendre en main les données dexemple"
},
"newCollection": {
"title": "Nouvelle {{collectionName}}",
"description": "Créer un nouveau conteneur pour le stockage et le débit"
},
"samplesGallery": {
"title": "Galerie déchantillons Azure Cosmos DB",
"description": "Découvrez des exemples qui présentent des modèles dapplication évolutifs et intelligents. Essayez-en un tout de suite pour voir à quelle vitesse vous pouvez passer du concept au code grâce à Cosmos DB"
},
"connectCard": {
"title": "Connecter",
"description": "Vous préférez utiliser vos propres outils ? Trouvez la chaîne de connexion dont vous avez besoin pour vous connecter",
"pgAdmin": {
"title": "Se connecter avec pgAdmin",
"description": "Préférez-vous pgAdmin ? Trouvez vos chaînes de connexion ici"
},
"vsCode": {
"title": "Connecter avec VS Code",
"description": "Interroger et gérer vos clusters MongoDB et DocumentDB dans Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "Interpréteur de commandes PostgreSQL",
"description": "Créer un tableau et interagir avec les données à laide de linterface dinterpréteur PostgreSQL"
},
"vcoreMongo": {
"title": "Interpréteur de commandes Mongo",
"description": "Créer une collection et interagir avec les données à laide de linterface dinterpréteur MongoDB"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "Vous débutez avec Cosmos DB PGSQL ?",
"body": "Bienvenue ! Si vous débutez avec Cosmos DB PGSQL et avez besoin daide pour démarrer, voici où trouver des échantillons de données et des requêtes."
},
"resetPassword": {
"headline": "Créer votre mot de passe",
"body": "Si vous navez pas encore modifié votre mot de passe, faites-le maintenant."
},
"coachMark": {
"headline": "Commencer par lexemple {{collectionName}}",
"body": "Nous vous guiderons dans la création dun conteneur dexemple avec des échantillons de données, puis nous vous ferons visiter lexplorateur de données. Vous pouvez également annuler cette visite et explorer par vous-même"
}
},
"sections": {
"recents": "Récents",
"clearRecents": "Effacer les éléments récents",
"top3": "Les 3 principales choses à savoir",
"learningResources": "Ressources pédagogiques",
"nextSteps": "Étapes suivantes",
"tipsAndLearnMore": "Conseils et plus dinformations",
"notebook": "Bloc-notes",
"needHelp": "Avez-vous besoin daide ?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Motifs de modélisation avancés",
"description": "Découvrez des stratégies avancées pour optimiser votre base de données."
},
"partitioning": {
"title": "Les meilleures pratiques de partitionnement",
"description": "Apprenez à appliquer des stratégies de modélisation des données et de partitionnement."
},
"resourcePlanning": {
"title": "Planifier vos besoins en ressources",
"description": "Découvrez les différentes options de configuration."
}
},
"mongo": {
"whatIsMongo": {
"title": "Quest-ce que lAPI MongoDB ?",
"description": "Comprenez Azure Cosmos DB for MongoDB et ses fonctionnalités."
},
"features": {
"title": "Fonctionnalités et syntaxe",
"description": "Découvrir les avantages et les fonctionnalités"
},
"migrate": {
"title": "Migrer vos données",
"description": "Étapes pré-migration pour le déplacement des données"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Créer une application Java",
"description": "Créez une application Java avec un SDK."
},
"partitioning": {
"title": "Les meilleures pratiques de partitionnement",
"description": "Découvrez comment fonctionne le partitionnement."
},
"requestUnits": {
"title": "Unités de requêtes (RU)",
"description": "Comprendre les frais de RU."
}
},
"gremlin": {
"dataModeling": {
"title": "Modélisation des données",
"description": "Recommandations pour la modélisation des données de Graph"
},
"partitioning": {
"title": "Les meilleures pratiques de partitionnement",
"description": "Découvrir comment fonctionne le partitionnement"
},
"queryData": {
"title": "Données de requête",
"description": "Interroger des données avec Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "Quest-ce que lAPI Table ?",
"description": "Comprendre Azure Cosmos DB for Table et ses fonctionnalités"
},
"migrate": {
"title": "Migrer vos données",
"description": "Découvrir comment migrer vos données"
},
"faq": {
"title": "FAQ Azure Cosmos DB for Table",
"description": "Questions courantes sur Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Raccourcis clavier pour Data Explorer",
"description": "Découvrez les raccourcis clavier pour naviguer dans Data Explorer."
},
"liveTv": {
"title": "Découvrir les principes de base",
"description": "Regardez lémission de télé en direct Azure Cosmos DB pour découvrir des vidéos dintroduction et des tutos."
},
"sql": {
"sdk": {
"title": "Prise en main dun SDK",
"description": "En savoir plus sur le SDK Azure Cosmos DB."
},
"migrate": {
"title": "Migrer vos données",
"description": "Migrez des données avec les services Azure et des solutions open source."
}
},
"mongo": {
"nodejs": {
"title": "Générer une application avec Node.js",
"description": "Créez une application Node.js."
},
"gettingStarted": {
"title": "Guide de prise en main",
"description": "Apprenez les notions de base pour démarrer."
}
},
"cassandra": {
"createContainer": {
"title": "Créer un conteneur",
"description": "Découvrez les options de création de conteneurs."
},
"throughput": {
"title": "Débit dapprovisionnement",
"description": "Découvrir comment configurer le débit."
}
},
"gremlin": {
"getStarted": {
"title": "Prise en main ",
"description": "Créer, interroger et parcourir avec la console Gremlin"
},
"importData": {
"title": "Importer les données de Graph",
"description": "Apprendre lingestion de données en bloc avec BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Créer une application .NET",
"description": "Comment accéder à Azure Cosmos DB for Table depuis une application .NET."
},
"java": {
"title": "Créer une application Java",
"description": "Créez une application Azure Cosmos DB for Table avec le SDK Java "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Modélisation des données",
"distributionColumn": "Comment choisir une colonne de distribution",
"buildApps": "Créer des applications avec Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrer des données",
"vectorSearch": "Créer des applications dIA avec la recherche vectorielle",
"buildApps": "Générer des applications avec Node.js"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Optimisation des performances",
"diagnosticQueries": "Requêtes de diagnostic utiles",
"sqlReference": "Référence SQL distribuée"
},
"vcoreMongo": {
"vectorSearch": "Recherche vectorielle",
"textIndexing": "Indexation de texte",
"troubleshoot": "Résoudre des problèmes courants"
}
},
"fabric": {
"buildTitle": "Générer votre base de données",
"useTitle": "Utiliser votre base de données",
"newContainer": {
"title": "Nouveau conteneur",
"description": "Créer un conteneur de destination pour stocker vos données"
},
"sampleData": {
"title": "Échantillons de données",
"description": "Charger des échantillons de données dans votre base de données"
},
"sampleVectorData": {
"title": "Échantillons de données vectorielles",
"description": "Charger des exemples de données vectorielles avec text-embedding-ada-002"
},
"appDevelopment": {
"title": "Développer des applications",
"description": "Commencer ici pour utiliser un SDK afin de créer vos applications"
},
"sampleGallery": {
"title": "Galerie déchantillons",
"description": "Obtenez des échantillons réels de bout en bout"
}
},
"sampleDataDialog": {
"title": "Échantillons de données",
"startButton": "Commencer",
"createPrompt": "Créez un conteneur « {{containerName}} » et importez-y des échantillons de données. Cela peut prendre quelques minutes.",
"creatingContainer": "Création en cours du conteneur « {{containerName}} »...",
"importingData": "Importation en cours de données dans « {{containerName}} »...",
"success": "Vous avez bien créé « {{containerName}} » avec des échantillons de données.",
"errorContainerExists": "Le conteneur « {{containerName}} » dans la base de données « {{databaseName}} » existe déjà. Supprimez-le, puis réessayez.",
"errorCreateContainer": "Nous navons pas pu créer le conteneur : {{error}}",
"errorImportData": "Nous navons pas pu importer les données : {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Mégse",
"close": "Bezárás",
"save": "Mentés",
"delete": "Törlés",
"update": "Frissítés",
"discard": "Elvetés",
"execute": "Execute",
"loading": "Betöltés folyamatban",
"loadingEllipsis": "Betöltés...",
"next": "Következő",
"previous": "Előző",
"yes": "Igen",
"no": "Nem",
"result": "Eredmény",
"learnMore": "További információ",
"getStarted": "Első lépések",
"retry": "Újrapróbálkozás",
"apply": "Alkalmaz",
"refresh": "Frissítés",
"copy": "Másolás",
"create": "Létrehozás",
"confirm": "Megerősítés",
"open": "Megnyitás",
"rename": "Átnevezés",
"download": "Letöltés",
"upload": "Feltöltés",
"connect": "Kapcsolódás",
"remove": "Eltávolítás",
"increaseValueBy1": "Érték növelése 1-gyel",
"decreaseValueBy1": "Érték csökkentése 1-gyel"
},
"splashScreen": {
"title": {
"default": "Üdvözli az Azure Cosmos DB",
"postgres": "Üdvözli az Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Üdvözli az Azure DocumentDB (MongoDB-kompatibilitással)"
},
"subtitle": {
"default": "Globálisan elosztott, többmodelles adatbázis-szolgáltatás bármilyen mérethez",
"getStarted": "Ismerje meg a minta adathalmazok, a dokumentáció és a további eszközök használatának első lépéseit."
},
"quickStart": {
"title": "Launch quick start",
"description": "Launch a quick start tutorial to get started with sample data"
},
"newCollection": {
"title": "New {{collectionName}}",
"description": "Create a new container for storage and throughput"
},
"samplesGallery": {
"title": "Azure Cosmos DB Samples Gallery",
"description": "Discover samples that showcase scalable, intelligent app patterns. Try one now to see how fast you can go from concept to code with Cosmos DB"
},
"connectCard": {
"title": "Connect",
"description": "Prefer using your own choice of tooling? Find the connection string you need to connect",
"pgAdmin": {
"title": "Connect with pgAdmin",
"description": "Prefer pgAdmin? Find your connection strings here"
},
"vsCode": {
"title": "Csatlakozás VS Code használatával",
"description": "Query and Manage your MongoDB and DocumentDB clusters in Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Create table and interact with data using PostgreSQL's shell interface"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Create a collection and interact with data using MongoDB's shell interface"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "New to Cosmos DB PGSQL?",
"body": "Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you can find sample data, query."
},
"resetPassword": {
"headline": "Create your password",
"body": "If you haven't changed your password yet, change it now."
},
"coachMark": {
"headline": "Start with sample {{collectionName}}",
"body": "You will be guided to create a sample container with sample data, then we will give you a tour of data explorer. You can also cancel launching this tour and explore yourself"
}
},
"sections": {
"recents": "Recents",
"clearRecents": "Clear Recents",
"top3": "Top 3 things you need to know",
"learningResources": "Learning Resources",
"nextSteps": "Next steps",
"tipsAndLearnMore": "Tips & learn more",
"notebook": "Notebook",
"needHelp": "Need help?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Advanced Modeling Patterns",
"description": "Learn advanced strategies to optimize your database."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn to apply data model and partitioning strategies."
},
"resourcePlanning": {
"title": "Plan Your Resource Requirements",
"description": "Get to know the different configuration choices."
}
},
"mongo": {
"whatIsMongo": {
"title": "What is the MongoDB API?",
"description": "Understand Azure Cosmos DB for MongoDB and its features."
},
"features": {
"title": "Features and Syntax",
"description": "Discover the advantages and features"
},
"migrate": {
"title": "Migrate Your Data",
"description": "Pre-migration steps for moving data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Build a Java App",
"description": "Create a Java app using an SDK."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works."
},
"requestUnits": {
"title": "Request Units (RUs)",
"description": "Understand RU charges."
}
},
"gremlin": {
"dataModeling": {
"title": "Data Modeling",
"description": "Graph data modeling recommendations"
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works"
},
"queryData": {
"title": "Query Data",
"description": "Querying data with Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "What is the Table API?",
"description": "Understand Azure Cosmos DB for Table and its features"
},
"migrate": {
"title": "Migrate your data",
"description": "Learn how to migrate your data"
},
"faq": {
"title": "Azure Cosmos DB for Table FAQs",
"description": "Common questions about Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Data Explorer keyboard shortcuts",
"description": "Learn keyboard shortcuts to navigate Data Explorer."
},
"liveTv": {
"title": "Learn the Fundamentals",
"description": "Watch Azure Cosmos DB Live TV show introductory and how to videos."
},
"sql": {
"sdk": {
"title": "Get Started using an SDK",
"description": "Learn about the Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrate Your Data",
"description": "Migrate data using Azure services and open-source solutions."
}
},
"mongo": {
"nodejs": {
"title": "Build an app with Node.js",
"description": "Create a Node.js app."
},
"gettingStarted": {
"title": "Getting Started Guide",
"description": "Learn the basics to get started."
}
},
"cassandra": {
"createContainer": {
"title": "Create a Container",
"description": "Get to know the create a container options."
},
"throughput": {
"title": "Provision Throughput",
"description": "Learn how to configure throughput."
}
},
"gremlin": {
"getStarted": {
"title": "Get Started ",
"description": "Create, query, and traverse using the Gremlin console"
},
"importData": {
"title": "Import Graph Data",
"description": "Learn Bulk ingestion data using BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Build a .NET App",
"description": "How to access Azure Cosmos DB for Table from a .NET app."
},
"java": {
"title": "Build a Java App",
"description": "Create a Azure Cosmos DB for Table app with Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Data Modeling",
"distributionColumn": "How to choose a Distribution Column",
"buildApps": "Build Apps with Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrate Data",
"vectorSearch": "Build AI apps with Vector Search",
"buildApps": "Build Apps with Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Performance Tuning",
"diagnosticQueries": "Useful Diagnostic Queries",
"sqlReference": "Distributed SQL Reference"
},
"vcoreMongo": {
"vectorSearch": "Vector Search",
"textIndexing": "Text Indexing",
"troubleshoot": "Troubleshoot common issues"
}
},
"fabric": {
"buildTitle": "Build your database",
"useTitle": "Use your database",
"newContainer": {
"title": "New container",
"description": "Create a destination container to store your data"
},
"sampleData": {
"title": "Sample Data",
"description": "Load sample data in your database"
},
"sampleVectorData": {
"title": "Sample Vector Data",
"description": "Load sample vector data with text-embedding-ada-002"
},
"appDevelopment": {
"title": "App development",
"description": "Start here to use an SDK to build your apps"
},
"sampleGallery": {
"title": "Sample Gallery",
"description": "Get real-world end-to-end samples"
}
},
"sampleDataDialog": {
"title": "Sample Data",
"startButton": "Start",
"createPrompt": "Create a container \"{{containerName}}\" and import sample data into it. This may take a few minutes.",
"creatingContainer": "Creating container \"{{containerName}}\"...",
"importingData": "Importing data into \"{{containerName}}\"...",
"success": "Successfully created \"{{containerName}}\" with sample data.",
"errorContainerExists": "The container \"{{containerName}}\" in database \"{{databaseName}}\" already exists. Please delete it and retry.",
"errorCreateContainer": "Failed to create container: {{error}}",
"errorImportData": "Failed to import data: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Batal",
"close": "Tutup",
"save": "Simpan",
"delete": "Hapus",
"update": "Perbarui",
"discard": "Buang",
"execute": "Jalankan",
"loading": "Memuat",
"loadingEllipsis": "Memuat...",
"next": "Berikutnya",
"previous": "Sebelumnya",
"yes": "Ya",
"no": "Tidak",
"result": "Hasil",
"learnMore": "Pelajari selengkapnya",
"getStarted": "Mulai",
"retry": "Coba lagi",
"apply": "Terapkan",
"refresh": "Refresh",
"copy": "Salin",
"create": "Buat",
"confirm": "Konfirmasi",
"open": "Buka",
"rename": "Ganti nama",
"download": "Unduh",
"upload": "Unggah",
"connect": "Sambungkan",
"remove": "Hapus",
"increaseValueBy1": "Tambah nilai sebesar 1",
"decreaseValueBy1": "Kurangi nilai sebesar 1"
},
"splashScreen": {
"title": {
"default": "Selamat Datang di Azure Cosmos DB",
"postgres": "Selamat datang di Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Selamat datang di Azure DocumentDB (dengan kompatibilitas MongoDB)"
},
"subtitle": {
"default": "Layanan database multimodel yang didistribusikan secara global untuk skala apa saja",
"getStarted": "Mulai dengan himpunan data sampel, dokumentasi, dan alat tambahan kami."
},
"quickStart": {
"title": "Luncurkan mulai cepat",
"description": "Mulai tutorial cepat untuk memulai dengan data sampel"
},
"newCollection": {
"title": "{{collectionName}} baru",
"description": "Buat kontainer baru untuk penyimpanan dan throughput"
},
"samplesGallery": {
"title": "Azure Cosmos DB Samples Gallery",
"description": "Temukan sampel yang menampilkan pola aplikasi cerdas yang dapat diskalakan. Coba sekarang untuk melihat seberapa cepat Anda bisa beralih dari konsep ke kode dengan Cosmos DB"
},
"connectCard": {
"title": "Sambungkan",
"description": "Lebih suka menggunakan alat pilihan sendiri? Temukan string koneksi yang diperlukan untuk menyambung",
"pgAdmin": {
"title": "Sambungkan dengan pgAdmin",
"description": "Lebih suka pgAdmin? Temukan string koneksi di sini"
},
"vsCode": {
"title": "Sambungkan dengan Visual Studio Code",
"description": "Kueri dan kelola klaster MongoDB dan DocumentDB di Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Buat tabel dan interaksi dengan data menggunakan antarmuka shell PostgreSQL"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Buat koleksi dan interaksi dengan data menggunakan antarmuka shell MongoDB"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "Baru menggunakan Cosmos DB PGSQL?",
"body": "Selamat datang! Jika baru menggunakan Cosmos DB PGSQL dan butuh bantuan memulai, di sini Anda dapat menemukan data sampel dan kueri."
},
"resetPassword": {
"headline": "Buat kata sandi Anda",
"body": "Jika belum mengubah kata sandi, ubah sekarang."
},
"coachMark": {
"headline": "Mulai dengan sampel {{collectionName}}",
"body": "Anda akan dipandu membuat kontainer sampel dengan data sampel, lalu kami akan memberikan tur penjelajah data. Anda juga bisa membatalkan tur ini dan menjelajah sendiri"
}
},
"sections": {
"recents": "Terbaru",
"clearRecents": "Bersihkan Riwayat Terbaru",
"top3": "3 Hal Terpenting yang Perlu Diketahui",
"learningResources": "Sumber Daya Pembelajaran",
"nextSteps": "Langkah berikutnya",
"tipsAndLearnMore": "Tips & pelajari selengkapnya",
"notebook": "Buku catatan",
"needHelp": "Perlu bantuan?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Pola Pemodelan Lanjutan",
"description": "Pelajari strategi lanjutan untuk mengoptimalkan database."
},
"partitioning": {
"title": "Praktik Terbaik Pemartisian",
"description": "Pelajari cara menerapkan model data dan strategi pemartisian."
},
"resourcePlanning": {
"title": "Rencanakan Kebutuhan Sumber Daya Anda",
"description": "Kenali Berbagai Pilihan Konfigurasi."
}
},
"mongo": {
"whatIsMongo": {
"title": "Apa itu API MongoDB?",
"description": "Pahami Azure Cosmos DB for MongoDB dan fitur-fiturnya."
},
"features": {
"title": "Fitur dan Sintaks",
"description": "Temukan Keunggulan dan Fitur"
},
"migrate": {
"title": "Migrasikan Data",
"description": "Langkah Pra-migrasi untuk Memindahkan Data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Buat Aplikasi Java",
"description": "Buat aplikasi Java menggunakan SDK."
},
"partitioning": {
"title": "Praktik Terbaik Pemartisian",
"description": "Pelajari cara kerja pemartisian."
},
"requestUnits": {
"title": "Unit Permintaan (RU)",
"description": "Pahami Biaya RU."
}
},
"gremlin": {
"dataModeling": {
"title": "Pemodelan Data",
"description": "Rekomendasi Pemodelan Data Grafik"
},
"partitioning": {
"title": "Praktik Terbaik Pemartisian",
"description": "Pelajari cara kerja partisi"
},
"queryData": {
"title": "Data Kueri",
"description": "Mengkueri data dengan Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "Apa itu Table API?",
"description": "Memahami Azure Cosmos DB for Table dan fiturnya"
},
"migrate": {
"title": "Migrasikan data Anda",
"description": "Pelajari cara memigrasikan data Anda"
},
"faq": {
"title": "Tanya Jawab Umum Azure Cosmos DB for Table",
"description": "Pertanyaan umum tentang Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Pintasan keyboard Data Explorer",
"description": "Pelajari pintasan keyboard untuk menavigasi Data Explorer."
},
"liveTv": {
"title": "Pelajari Dasar",
"description": "Tonton video perkenalan dan tutorial Azure Cosmos DB Live TV."
},
"sql": {
"sdk": {
"title": "Mulai menggunakan SDK",
"description": "Pelajari tentang Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrasikan Data",
"description": "Migrasikan data menggunakan layanan Azure dan solusi sumber terbuka."
}
},
"mongo": {
"nodejs": {
"title": "Buat aplikasi dengan Node.js",
"description": "Buat aplikasi Node.js."
},
"gettingStarted": {
"title": "Panduan Persiapan",
"description": "Pelajari dasar untuk memulai."
}
},
"cassandra": {
"createContainer": {
"title": "Buat Kontainer",
"description": "Kenali opsi buat kontainer."
},
"throughput": {
"title": "Throughput Penyediaan",
"description": "Pelajari cara mengonfigurasi throughput."
}
},
"gremlin": {
"getStarted": {
"title": "Mulai ",
"description": "Buat, kueri, dan jelajahi menggunakan konsol Gremlin"
},
"importData": {
"title": "Impor Data Graf",
"description": "Pelajari penyerapan massal data menggunakan BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Buat Aplikasi .NET",
"description": "Cara mengakses Azure Cosmos DB for Table dari aplikasi .NET."
},
"java": {
"title": "Buat Aplikasi Java",
"description": "Buat aplikasi Azure Cosmos DB for Table dengan Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Pemodelan Data",
"distributionColumn": "Cara memilih Kolom Distribusi",
"buildApps": "Buat Aplikasi dengan Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrasikan Data",
"vectorSearch": "Buat aplikasi AI dengan Pencarian Vektor",
"buildApps": "Buat Aplikasi dengan Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Penyetelan Performa",
"diagnosticQueries": "Kueri Diagnostik yang Berguna",
"sqlReference": "Referensi SQL Terdistribusi"
},
"vcoreMongo": {
"vectorSearch": "Pencarian Vektor",
"textIndexing": "Pengindeksan Teks",
"troubleshoot": "Pecahkan masalah umum"
}
},
"fabric": {
"buildTitle": "Bangun database Anda",
"useTitle": "Gunakan database Anda",
"newContainer": {
"title": "Kontainer baru",
"description": "Buat kontainer tujuan untuk menyimpan data"
},
"sampleData": {
"title": "Data Sampel",
"description": "Muat data sampel ke database"
},
"sampleVectorData": {
"title": "Data Vektor Sampel",
"description": "Muat data vektor sampel dengan text-embedding-ada-002"
},
"appDevelopment": {
"title": "Pengembangan aplikasi",
"description": "Mulai di sini untuk menggunakan SDK membangun aplikasi"
},
"sampleGallery": {
"title": "Galeri Sampel",
"description": "Dapatkan sampel menyeluruh dunia nyata"
}
},
"sampleDataDialog": {
"title": "Data Sampel",
"startButton": "Mulai",
"createPrompt": "Buat kontainer \"{{containerName}}\" dan impor data sampel ke dalamnya. Proses ini memerlukan waktu beberapa menit.",
"creatingContainer": "Membuat kontainer \"{{containerName}}\"...",
"importingData": "Mengimpor data ke \"{{containerName}}\"...",
"success": "Berhasil membuat \"{{containerName}}\" dengan data sampel.",
"errorContainerExists": "Kontainer \"{{containerName}}\" di database \"{{databaseName}}\" sudah ada. Hapus dan coba lagi.",
"errorCreateContainer": "Gagal membuat kontainer: {{error}}",
"errorImportData": "Gagal mengimpor data: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Annulla",
"close": "Chiudi",
"save": "Salva",
"delete": "Elimina",
"update": "Aggiorna",
"discard": "Rimuovi",
"execute": "Execute",
"loading": "Caricamento",
"loadingEllipsis": "Caricamento...",
"next": "Avanti",
"previous": "Indietro",
"yes": "Sì",
"no": "No",
"result": "Risultato",
"learnMore": "Altre informazioni",
"getStarted": "Attività iniziali",
"retry": "Riprova",
"apply": "Applica",
"refresh": "Aggiorna",
"copy": "Copia",
"create": "Crea",
"confirm": "Conferma",
"open": "Apri",
"rename": "Rinomina",
"download": "Scarica",
"upload": "Carica",
"connect": "Connetti",
"remove": "Rimuovi",
"increaseValueBy1": "Aumentare il valore di 1",
"decreaseValueBy1": "Diminuisci il valore di 1"
},
"splashScreen": {
"title": {
"default": "Benvenuto in Azure Cosmos DB",
"postgres": "Benvenuti in Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Benvenuti in Azure DocumentDB (con compatibilità MongoDB)"
},
"subtitle": {
"default": "Servizio database multimodello distribuito a livello globale a qualsiasi livello di scalabilità",
"getStarted": "Inizia con i nostri set di dati di esempio, la documentazione e gli strumenti aggiuntivi."
},
"quickStart": {
"title": "Launch quick start",
"description": "Launch a quick start tutorial to get started with sample data"
},
"newCollection": {
"title": "New {{collectionName}}",
"description": "Create a new container for storage and throughput"
},
"samplesGallery": {
"title": "Azure Cosmos DB Samples Gallery",
"description": "Discover samples that showcase scalable, intelligent app patterns. Try one now to see how fast you can go from concept to code with Cosmos DB"
},
"connectCard": {
"title": "Connect",
"description": "Prefer using your own choice of tooling? Find the connection string you need to connect",
"pgAdmin": {
"title": "Connect with pgAdmin",
"description": "Prefer pgAdmin? Find your connection strings here"
},
"vsCode": {
"title": "Connetti con VS Code",
"description": "Query and Manage your MongoDB and DocumentDB clusters in Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Create table and interact with data using PostgreSQL's shell interface"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Create a collection and interact with data using MongoDB's shell interface"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "New to Cosmos DB PGSQL?",
"body": "Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you can find sample data, query."
},
"resetPassword": {
"headline": "Create your password",
"body": "If you haven't changed your password yet, change it now."
},
"coachMark": {
"headline": "Start with sample {{collectionName}}",
"body": "You will be guided to create a sample container with sample data, then we will give you a tour of data explorer. You can also cancel launching this tour and explore yourself"
}
},
"sections": {
"recents": "Recents",
"clearRecents": "Clear Recents",
"top3": "Top 3 things you need to know",
"learningResources": "Learning Resources",
"nextSteps": "Next steps",
"tipsAndLearnMore": "Tips & learn more",
"notebook": "Notebook",
"needHelp": "Need help?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Advanced Modeling Patterns",
"description": "Learn advanced strategies to optimize your database."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn to apply data model and partitioning strategies."
},
"resourcePlanning": {
"title": "Plan Your Resource Requirements",
"description": "Get to know the different configuration choices."
}
},
"mongo": {
"whatIsMongo": {
"title": "What is the MongoDB API?",
"description": "Understand Azure Cosmos DB for MongoDB and its features."
},
"features": {
"title": "Features and Syntax",
"description": "Discover the advantages and features"
},
"migrate": {
"title": "Migrate Your Data",
"description": "Pre-migration steps for moving data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Build a Java App",
"description": "Create a Java app using an SDK."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works."
},
"requestUnits": {
"title": "Request Units (RUs)",
"description": "Understand RU charges."
}
},
"gremlin": {
"dataModeling": {
"title": "Data Modeling",
"description": "Graph data modeling recommendations"
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works"
},
"queryData": {
"title": "Query Data",
"description": "Querying data with Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "What is the Table API?",
"description": "Understand Azure Cosmos DB for Table and its features"
},
"migrate": {
"title": "Migrate your data",
"description": "Learn how to migrate your data"
},
"faq": {
"title": "Azure Cosmos DB for Table FAQs",
"description": "Common questions about Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Data Explorer keyboard shortcuts",
"description": "Learn keyboard shortcuts to navigate Data Explorer."
},
"liveTv": {
"title": "Learn the Fundamentals",
"description": "Watch Azure Cosmos DB Live TV show introductory and how to videos."
},
"sql": {
"sdk": {
"title": "Get Started using an SDK",
"description": "Learn about the Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrate Your Data",
"description": "Migrate data using Azure services and open-source solutions."
}
},
"mongo": {
"nodejs": {
"title": "Build an app with Node.js",
"description": "Create a Node.js app."
},
"gettingStarted": {
"title": "Getting Started Guide",
"description": "Learn the basics to get started."
}
},
"cassandra": {
"createContainer": {
"title": "Create a Container",
"description": "Get to know the create a container options."
},
"throughput": {
"title": "Provision Throughput",
"description": "Learn how to configure throughput."
}
},
"gremlin": {
"getStarted": {
"title": "Get Started ",
"description": "Create, query, and traverse using the Gremlin console"
},
"importData": {
"title": "Import Graph Data",
"description": "Learn Bulk ingestion data using BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Build a .NET App",
"description": "How to access Azure Cosmos DB for Table from a .NET app."
},
"java": {
"title": "Build a Java App",
"description": "Create a Azure Cosmos DB for Table app with Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Data Modeling",
"distributionColumn": "How to choose a Distribution Column",
"buildApps": "Build Apps with Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrate Data",
"vectorSearch": "Build AI apps with Vector Search",
"buildApps": "Build Apps with Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Performance Tuning",
"diagnosticQueries": "Useful Diagnostic Queries",
"sqlReference": "Distributed SQL Reference"
},
"vcoreMongo": {
"vectorSearch": "Vector Search",
"textIndexing": "Text Indexing",
"troubleshoot": "Troubleshoot common issues"
}
},
"fabric": {
"buildTitle": "Build your database",
"useTitle": "Use your database",
"newContainer": {
"title": "New container",
"description": "Create a destination container to store your data"
},
"sampleData": {
"title": "Sample Data",
"description": "Load sample data in your database"
},
"sampleVectorData": {
"title": "Sample Vector Data",
"description": "Load sample vector data with text-embedding-ada-002"
},
"appDevelopment": {
"title": "App development",
"description": "Start here to use an SDK to build your apps"
},
"sampleGallery": {
"title": "Sample Gallery",
"description": "Get real-world end-to-end samples"
}
},
"sampleDataDialog": {
"title": "Sample Data",
"startButton": "Start",
"createPrompt": "Create a container \"{{containerName}}\" and import sample data into it. This may take a few minutes.",
"creatingContainer": "Creating container \"{{containerName}}\"...",
"importingData": "Importing data into \"{{containerName}}\"...",
"success": "Successfully created \"{{containerName}}\" with sample data.",
"errorContainerExists": "The container \"{{containerName}}\" in database \"{{databaseName}}\" already exists. Please delete it and retry.",
"errorCreateContainer": "Failed to create container: {{error}}",
"errorImportData": "Failed to import data: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "キャンセル",
"close": "閉じる",
"save": "保存",
"delete": "削除",
"update": "更新",
"discard": "破棄",
"execute": "Execute",
"loading": "読み込み中",
"loadingEllipsis": "読み込み中...",
"next": "次へ",
"previous": "前へ",
"yes": "はい",
"no": "いいえ",
"result": "結果",
"learnMore": "詳細情報",
"getStarted": "開始する",
"retry": "再試行",
"apply": "適用",
"refresh": "最新の情報に更新",
"copy": "コピー",
"create": "作成",
"confirm": "確認",
"open": "開く",
"rename": "名前の変更",
"download": "ダウンロード",
"upload": "アップロード",
"connect": "接続",
"remove": "削除",
"increaseValueBy1": "値を 1 増加",
"decreaseValueBy1": "値を 1 減少"
},
"splashScreen": {
"title": {
"default": "Azure Cosmos DB へようこそ",
"postgres": "Azure Cosmos DB for PostgreSQL へようこそ",
"vcoreMongo": "Azure DocumentDB (MongoDB 互換) へようこそ"
},
"subtitle": {
"default": "あらゆるスケールに対応するグローバル分散型のマルチモデル データベース サーバー",
"getStarted": "サンプル データセット、ドキュメント、追加ツールを使用して開始してください。"
},
"quickStart": {
"title": "Launch quick start",
"description": "Launch a quick start tutorial to get started with sample data"
},
"newCollection": {
"title": "New {{collectionName}}",
"description": "Create a new container for storage and throughput"
},
"samplesGallery": {
"title": "Azure Cosmos DB Samples Gallery",
"description": "Discover samples that showcase scalable, intelligent app patterns. Try one now to see how fast you can go from concept to code with Cosmos DB"
},
"connectCard": {
"title": "Connect",
"description": "Prefer using your own choice of tooling? Find the connection string you need to connect",
"pgAdmin": {
"title": "Connect with pgAdmin",
"description": "Prefer pgAdmin? Find your connection strings here"
},
"vsCode": {
"title": "VS Code で接続する",
"description": "Query and Manage your MongoDB and DocumentDB clusters in Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Create table and interact with data using PostgreSQL's shell interface"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Create a collection and interact with data using MongoDB's shell interface"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "New to Cosmos DB PGSQL?",
"body": "Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you can find sample data, query."
},
"resetPassword": {
"headline": "Create your password",
"body": "If you haven't changed your password yet, change it now."
},
"coachMark": {
"headline": "Start with sample {{collectionName}}",
"body": "You will be guided to create a sample container with sample data, then we will give you a tour of data explorer. You can also cancel launching this tour and explore yourself"
}
},
"sections": {
"recents": "Recents",
"clearRecents": "Clear Recents",
"top3": "Top 3 things you need to know",
"learningResources": "Learning Resources",
"nextSteps": "Next steps",
"tipsAndLearnMore": "Tips & learn more",
"notebook": "Notebook",
"needHelp": "Need help?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Advanced Modeling Patterns",
"description": "Learn advanced strategies to optimize your database."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn to apply data model and partitioning strategies."
},
"resourcePlanning": {
"title": "Plan Your Resource Requirements",
"description": "Get to know the different configuration choices."
}
},
"mongo": {
"whatIsMongo": {
"title": "What is the MongoDB API?",
"description": "Understand Azure Cosmos DB for MongoDB and its features."
},
"features": {
"title": "Features and Syntax",
"description": "Discover the advantages and features"
},
"migrate": {
"title": "Migrate Your Data",
"description": "Pre-migration steps for moving data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Build a Java App",
"description": "Create a Java app using an SDK."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works."
},
"requestUnits": {
"title": "Request Units (RUs)",
"description": "Understand RU charges."
}
},
"gremlin": {
"dataModeling": {
"title": "Data Modeling",
"description": "Graph data modeling recommendations"
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works"
},
"queryData": {
"title": "Query Data",
"description": "Querying data with Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "What is the Table API?",
"description": "Understand Azure Cosmos DB for Table and its features"
},
"migrate": {
"title": "Migrate your data",
"description": "Learn how to migrate your data"
},
"faq": {
"title": "Azure Cosmos DB for Table FAQs",
"description": "Common questions about Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Data Explorer keyboard shortcuts",
"description": "Learn keyboard shortcuts to navigate Data Explorer."
},
"liveTv": {
"title": "Learn the Fundamentals",
"description": "Watch Azure Cosmos DB Live TV show introductory and how to videos."
},
"sql": {
"sdk": {
"title": "Get Started using an SDK",
"description": "Learn about the Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrate Your Data",
"description": "Migrate data using Azure services and open-source solutions."
}
},
"mongo": {
"nodejs": {
"title": "Build an app with Node.js",
"description": "Create a Node.js app."
},
"gettingStarted": {
"title": "Getting Started Guide",
"description": "Learn the basics to get started."
}
},
"cassandra": {
"createContainer": {
"title": "Create a Container",
"description": "Get to know the create a container options."
},
"throughput": {
"title": "Provision Throughput",
"description": "Learn how to configure throughput."
}
},
"gremlin": {
"getStarted": {
"title": "Get Started ",
"description": "Create, query, and traverse using the Gremlin console"
},
"importData": {
"title": "Import Graph Data",
"description": "Learn Bulk ingestion data using BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Build a .NET App",
"description": "How to access Azure Cosmos DB for Table from a .NET app."
},
"java": {
"title": "Build a Java App",
"description": "Create a Azure Cosmos DB for Table app with Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Data Modeling",
"distributionColumn": "How to choose a Distribution Column",
"buildApps": "Build Apps with Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrate Data",
"vectorSearch": "Build AI apps with Vector Search",
"buildApps": "Build Apps with Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Performance Tuning",
"diagnosticQueries": "Useful Diagnostic Queries",
"sqlReference": "Distributed SQL Reference"
},
"vcoreMongo": {
"vectorSearch": "Vector Search",
"textIndexing": "Text Indexing",
"troubleshoot": "Troubleshoot common issues"
}
},
"fabric": {
"buildTitle": "Build your database",
"useTitle": "Use your database",
"newContainer": {
"title": "New container",
"description": "Create a destination container to store your data"
},
"sampleData": {
"title": "Sample Data",
"description": "Load sample data in your database"
},
"sampleVectorData": {
"title": "Sample Vector Data",
"description": "Load sample vector data with text-embedding-ada-002"
},
"appDevelopment": {
"title": "App development",
"description": "Start here to use an SDK to build your apps"
},
"sampleGallery": {
"title": "Sample Gallery",
"description": "Get real-world end-to-end samples"
}
},
"sampleDataDialog": {
"title": "Sample Data",
"startButton": "Start",
"createPrompt": "Create a container \"{{containerName}}\" and import sample data into it. This may take a few minutes.",
"creatingContainer": "Creating container \"{{containerName}}\"...",
"importingData": "Importing data into \"{{containerName}}\"...",
"success": "Successfully created \"{{containerName}}\" with sample data.",
"errorContainerExists": "The container \"{{containerName}}\" in database \"{{databaseName}}\" already exists. Please delete it and retry.",
"errorCreateContainer": "Failed to create container: {{error}}",
"errorImportData": "Failed to import data: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "확인",
"cancel": "취소",
"close": "닫기",
"save": "저장",
"delete": "삭제",
"update": "업데이트",
"discard": "삭제",
"execute": "실행",
"loading": "로드 중",
"loadingEllipsis": "로드 중...",
"next": "다음",
"previous": "이전",
"yes": "예",
"no": "아니요",
"result": "결과",
"learnMore": "자세한 정보",
"getStarted": "시작",
"retry": "다시 시도",
"apply": "적용",
"refresh": "새로 고침",
"copy": "복사",
"create": "만들기",
"confirm": "확인",
"open": "열기",
"rename": "이름 바꾸기",
"download": "다운로드",
"upload": "업로드",
"connect": "연결",
"remove": "제거",
"increaseValueBy1": "값을 1만큼 늘리기",
"decreaseValueBy1": "값을 1만큼 줄이기"
},
"splashScreen": {
"title": {
"default": "Azure Cosmos DB 시작",
"postgres": "Azure Cosmos DB for PostgreSQL 시작",
"vcoreMongo": "Azure DocumentDB 시작(MongoDB 호환성 포함)"
},
"subtitle": {
"default": "모든 규모에 대해 전역적으로 분산된 다중 모델 데이터베이스 서비스",
"getStarted": "샘플 데이터 세트, 설명서 및 추가 도구를 시작하세요."
},
"quickStart": {
"title": "빠른 시작 개시",
"description": "빠른 시작 자습서를 시작하여 샘플 데이터 시작"
},
"newCollection": {
"title": "새 {{collectionName}}",
"description": "스토리지 및 처리량에 대한 새 컨테이너 만들기"
},
"samplesGallery": {
"title": "Azure Cosmos DB 샘플 갤러리",
"description": "확장성 있는 인텔리전트 앱 패턴을 보여 주는 샘플을 검색합니다. Cosmos DB 사용하여 개념에서 코드로 얼마나 빨리 이동할 수 있는지 확인해 보세요."
},
"connectCard": {
"title": "연결",
"description": "원하는 도구 사용을 선호하시나요? 연결해야 하는 연결 문자열 찾기",
"pgAdmin": {
"title": "pgAdmin으로 연결",
"description": "pgAdmin을 선호하시나요? 여기에서 연결 문자열 찾기"
},
"vsCode": {
"title": "VS Code와 연결",
"description": "Visual Studio Code MongoDB 및 DocumentDB 클러스터 쿼리 및 관리"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL 셸",
"description": "PostgreSQL의 셸 인터페이스를 사용하여 테이블 만들기 및 데이터 조작"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "MongoDB의 셸 인터페이스를 사용하여 컬렉션 만들기 및 데이터 조작"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "PGSQL을 Cosmos DB?",
"body": "환영합니다. PGSQL을 Cosmos DB 시작에 대한 도움이 필요한 경우 샘플 데이터, 쿼리를 찾을 수 있는 위치는 다음과 같습니다."
},
"resetPassword": {
"headline": "암호 만들기",
"body": "암호를 아직 변경하지 않은 경우 지금 변경하세요."
},
"coachMark": {
"headline": "샘플 {{collectionName}} 시작",
"body": "샘플 데이터를 사용하여 샘플 컨테이너를 만드는 과정을 안내한 다음 데이터 탐색기를 둘러보겠습니다. 이 둘러보기 시작을 취소하고 직접 탐색할 수도 있습니다."
}
},
"sections": {
"recents": "최근 항목",
"clearRecents": "최근 항목 지우기",
"top3": "꼭 알아야 할 3가지",
"learningResources": "학습 리소스",
"nextSteps": "다음 단계",
"tipsAndLearnMore": "팁 및 자세한 정보",
"notebook": "Notebook",
"needHelp": "도움이 필요하세요?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "고급 모델링 패턴",
"description": "데이터베이스를 최적화하기 위한 고급 전략을 알아봅니다."
},
"partitioning": {
"title": "분할 모범 사례",
"description": "데이터 모델 및 분할 전략을 적용하는 방법을 알아봅니다."
},
"resourcePlanning": {
"title": "리소스 요구 사항 계획",
"description": "다양한 구성 선택 사항에 대해 알아보세요."
}
},
"mongo": {
"whatIsMongo": {
"title": "MongoDB API란?",
"description": "MongoDB 및 해당 기능에 대한 Azure Cosmos DB 이해합니다."
},
"features": {
"title": "기능 및 구문",
"description": "장점 및 기능 살펴보기"
},
"migrate": {
"title": "데이터 마이그레이션",
"description": "데이터 이동을 위한 마이그레이션 전 단계"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Java 앱 빌드",
"description": "SDK를 사용하여 Java 앱을 만듭니다."
},
"partitioning": {
"title": "분할 모범 사례",
"description": "분할의 작동 방식을 알아봅니다."
},
"requestUnits": {
"title": "RU(요청 단위)",
"description": "RU 요금을 이해합니다."
}
},
"gremlin": {
"dataModeling": {
"title": "데이터 모델링",
"description": "그래프 데이터 모델링 권장 사항"
},
"partitioning": {
"title": "분할 모범 사례",
"description": "분할의 작동 방식 알아보기"
},
"queryData": {
"title": "데이터 쿼리",
"description": "Gremlin을 사용하여 데이터 쿼리"
}
},
"tables": {
"whatIsTable": {
"title": "Table API 무엇인가요?",
"description": "테이블 및 해당 기능에 대한 Azure Cosmos DB 이해"
},
"migrate": {
"title": "데이터 마이그레이션",
"description": "데이터 마이그레이션 방법 알아보기"
},
"faq": {
"title": "테이블 FAQ에 대한 Azure Cosmos DB",
"description": "테이블 Azure Cosmos DB 대한 일반적인 질문"
}
}
},
"learningResources": {
"shortcuts": {
"title": "바로 가기 키 데이터 탐색기",
"description": "Data Explorer를 탐색하는 키보드 단축키를 배워보세요."
},
"liveTv": {
"title": "기본 사항 알아보기",
"description": "Azure Cosmos DB Live TV 쇼 소개 및 비디오 방법을 시청하세요."
},
"sql": {
"sdk": {
"title": "SDK 사용 시작",
"description": "Azure Cosmos DB SDK에 대해 알아봅니다."
},
"migrate": {
"title": "데이터 마이그레이션",
"description": "Azure 서비스 및 오픈 소스 솔루션을 사용하여 데이터를 마이그레이션합니다."
}
},
"mongo": {
"nodejs": {
"title": "Node.js 사용하여 앱 빌드",
"description": "Node.js 앱을 만듭니다."
},
"gettingStarted": {
"title": "시작 가이드",
"description": "시작하는 데 필요한 기본 사항을 알아보세요."
}
},
"cassandra": {
"createContainer": {
"title": "컨테이너 만들기",
"description": "컨테이너 만들기 옵션을 알아보세요."
},
"throughput": {
"title": "처리량 프로비저닝",
"description": "처리량을 구성하는 방법을 알아봅니다."
}
},
"gremlin": {
"getStarted": {
"title": "시작 ",
"description": "Gremlin 콘솔을 사용하여 만들기, 쿼리 및 트래버스"
},
"importData": {
"title": "Graph 데이터 가져오기",
"description": "BulkExecutor를 사용하여 대량 수집 데이터 알아보기"
}
},
"tables": {
"dotnet": {
"title": ".NET 앱 만들기",
"description": ".NET 앱에서 Table용 Azure Cosmos DB에 액세스하는 방법입니다."
},
"java": {
"title": "Java 앱 빌드",
"description": "Java SDK를 사용하여 Table 앱에 대한 Azure Cosmos DB 만들기 "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "데이터 모델링",
"distributionColumn": "배포 열을 선택하는 방법",
"buildApps": "Python/Java/Django를 사용하여 앱 빌드"
},
"vcoreMongo": {
"migrateData": "데이터 마이그레이션",
"vectorSearch": "벡터 검색을 사용하여 AI 앱 빌드",
"buildApps": "Nodejs를 사용하여 앱 빌드"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "성능 튜닝",
"diagnosticQueries": "유용한 진단 쿼리",
"sqlReference": "분산 SQL 참조"
},
"vcoreMongo": {
"vectorSearch": "벡터 검색",
"textIndexing": "텍스트 인덱싱",
"troubleshoot": "일반적인 문제 해결"
}
},
"fabric": {
"buildTitle": "데이터베이스 빌드",
"useTitle": "데이터베이스 사용",
"newContainer": {
"title": "새 컨테이너",
"description": "데이터를 저장할 대상 컨테이너 만들기"
},
"sampleData": {
"title": "샘플 데이터",
"description": "데이터베이스에 샘플 데이터 로드"
},
"sampleVectorData": {
"title": "샘플 벡터 데이터",
"description": "text-embedding-ada-002를 사용하여 샘플 벡터 데이터 로드"
},
"appDevelopment": {
"title": "앱 개발",
"description": "SDK를 사용하여 앱을 빌드하려면 여기에서 시작하세요."
},
"sampleGallery": {
"title": "샘플 갤러리",
"description": "실제 엔드 투 엔드 샘플 가져오기"
}
},
"sampleDataDialog": {
"title": "샘플 데이터",
"startButton": "시작",
"createPrompt": "\"{{containerName}}\" 컨테이너를 만들고 샘플 데이터를 해당 컨테이너로 가져옵니다. 몇 분 정도 걸릴 수 있습니다.",
"creatingContainer": "컨테이너 \"{{containerName}}\"을(를) 만드는 중...",
"importingData": "\"{{containerName}}\"로 데이터를 가져오는 중...",
"success": "샘플 데이터를 사용하여 \"{{containerName}}\"을 만들었습니다.",
"errorContainerExists": "데이터베이스 \"{{databaseName}}\"의 컨테이너 \"{{containerName}}\"이(가) 이미 있습니다. 삭제하고 다시 시도하세요.",
"errorCreateContainer": "컨테이너를 만들지 못했습니다. {{error}}",
"errorImportData": "데이터를 가져오지 못했습니다. {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Annuleren",
"close": "Sluiten",
"save": "Opslaan",
"delete": "Verwijderen",
"update": "Bijwerken",
"discard": "Negeren",
"execute": "Execute",
"loading": "Laden",
"loadingEllipsis": "Laden...",
"next": "Volgende",
"previous": "Vorige",
"yes": "Ja",
"no": "Nee",
"result": "Resultaat",
"learnMore": "Meer informatie",
"getStarted": "Aan de slag",
"retry": "Opnieuw proberen",
"apply": "Toepassen",
"refresh": "Vernieuwen",
"copy": "Kopiëren",
"create": "Maken",
"confirm": "Bevestigen",
"open": "Open",
"rename": "Naam wijzigen",
"download": "Downloaden",
"upload": "Uploaden",
"connect": "Verbinding maken",
"remove": "Verwijderen",
"increaseValueBy1": "Waarde verhogen met 1",
"decreaseValueBy1": "Waarde verlagen met 1"
},
"splashScreen": {
"title": {
"default": "Welkom bij Azure Cosmos DB",
"postgres": "Welkom bij Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Welkom bij Azure DocumentDB (met MongoDB-compatibiliteit)"
},
"subtitle": {
"default": "Wereldwijd gedistribueerde, multi-modeldatabase-service voor elke schaalgrootte",
"getStarted": "Ga aan de slag met onze voorbeelddatasets, documentatie en extra tools."
},
"quickStart": {
"title": "Launch quick start",
"description": "Launch a quick start tutorial to get started with sample data"
},
"newCollection": {
"title": "New {{collectionName}}",
"description": "Create a new container for storage and throughput"
},
"samplesGallery": {
"title": "Azure Cosmos DB Samples Gallery",
"description": "Discover samples that showcase scalable, intelligent app patterns. Try one now to see how fast you can go from concept to code with Cosmos DB"
},
"connectCard": {
"title": "Connect",
"description": "Prefer using your own choice of tooling? Find the connection string you need to connect",
"pgAdmin": {
"title": "Connect with pgAdmin",
"description": "Prefer pgAdmin? Find your connection strings here"
},
"vsCode": {
"title": "Verbinding maken met VS Code",
"description": "Query and Manage your MongoDB and DocumentDB clusters in Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Create table and interact with data using PostgreSQL's shell interface"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Create a collection and interact with data using MongoDB's shell interface"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "New to Cosmos DB PGSQL?",
"body": "Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you can find sample data, query."
},
"resetPassword": {
"headline": "Create your password",
"body": "If you haven't changed your password yet, change it now."
},
"coachMark": {
"headline": "Start with sample {{collectionName}}",
"body": "You will be guided to create a sample container with sample data, then we will give you a tour of data explorer. You can also cancel launching this tour and explore yourself"
}
},
"sections": {
"recents": "Recents",
"clearRecents": "Clear Recents",
"top3": "Top 3 things you need to know",
"learningResources": "Learning Resources",
"nextSteps": "Next steps",
"tipsAndLearnMore": "Tips & learn more",
"notebook": "Notebook",
"needHelp": "Need help?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Advanced Modeling Patterns",
"description": "Learn advanced strategies to optimize your database."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn to apply data model and partitioning strategies."
},
"resourcePlanning": {
"title": "Plan Your Resource Requirements",
"description": "Get to know the different configuration choices."
}
},
"mongo": {
"whatIsMongo": {
"title": "What is the MongoDB API?",
"description": "Understand Azure Cosmos DB for MongoDB and its features."
},
"features": {
"title": "Features and Syntax",
"description": "Discover the advantages and features"
},
"migrate": {
"title": "Migrate Your Data",
"description": "Pre-migration steps for moving data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Build a Java App",
"description": "Create a Java app using an SDK."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works."
},
"requestUnits": {
"title": "Request Units (RUs)",
"description": "Understand RU charges."
}
},
"gremlin": {
"dataModeling": {
"title": "Data Modeling",
"description": "Graph data modeling recommendations"
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works"
},
"queryData": {
"title": "Query Data",
"description": "Querying data with Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "What is the Table API?",
"description": "Understand Azure Cosmos DB for Table and its features"
},
"migrate": {
"title": "Migrate your data",
"description": "Learn how to migrate your data"
},
"faq": {
"title": "Azure Cosmos DB for Table FAQs",
"description": "Common questions about Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Data Explorer keyboard shortcuts",
"description": "Learn keyboard shortcuts to navigate Data Explorer."
},
"liveTv": {
"title": "Learn the Fundamentals",
"description": "Watch Azure Cosmos DB Live TV show introductory and how to videos."
},
"sql": {
"sdk": {
"title": "Get Started using an SDK",
"description": "Learn about the Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrate Your Data",
"description": "Migrate data using Azure services and open-source solutions."
}
},
"mongo": {
"nodejs": {
"title": "Build an app with Node.js",
"description": "Create a Node.js app."
},
"gettingStarted": {
"title": "Getting Started Guide",
"description": "Learn the basics to get started."
}
},
"cassandra": {
"createContainer": {
"title": "Create a Container",
"description": "Get to know the create a container options."
},
"throughput": {
"title": "Provision Throughput",
"description": "Learn how to configure throughput."
}
},
"gremlin": {
"getStarted": {
"title": "Get Started ",
"description": "Create, query, and traverse using the Gremlin console"
},
"importData": {
"title": "Import Graph Data",
"description": "Learn Bulk ingestion data using BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Build a .NET App",
"description": "How to access Azure Cosmos DB for Table from a .NET app."
},
"java": {
"title": "Build a Java App",
"description": "Create a Azure Cosmos DB for Table app with Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Data Modeling",
"distributionColumn": "How to choose a Distribution Column",
"buildApps": "Build Apps with Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrate Data",
"vectorSearch": "Build AI apps with Vector Search",
"buildApps": "Build Apps with Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Performance Tuning",
"diagnosticQueries": "Useful Diagnostic Queries",
"sqlReference": "Distributed SQL Reference"
},
"vcoreMongo": {
"vectorSearch": "Vector Search",
"textIndexing": "Text Indexing",
"troubleshoot": "Troubleshoot common issues"
}
},
"fabric": {
"buildTitle": "Build your database",
"useTitle": "Use your database",
"newContainer": {
"title": "New container",
"description": "Create a destination container to store your data"
},
"sampleData": {
"title": "Sample Data",
"description": "Load sample data in your database"
},
"sampleVectorData": {
"title": "Sample Vector Data",
"description": "Load sample vector data with text-embedding-ada-002"
},
"appDevelopment": {
"title": "App development",
"description": "Start here to use an SDK to build your apps"
},
"sampleGallery": {
"title": "Sample Gallery",
"description": "Get real-world end-to-end samples"
}
},
"sampleDataDialog": {
"title": "Sample Data",
"startButton": "Start",
"createPrompt": "Create a container \"{{containerName}}\" and import sample data into it. This may take a few minutes.",
"creatingContainer": "Creating container \"{{containerName}}\"...",
"importingData": "Importing data into \"{{containerName}}\"...",
"success": "Successfully created \"{{containerName}}\" with sample data.",
"errorContainerExists": "The container \"{{containerName}}\" in database \"{{databaseName}}\" already exists. Please delete it and retry.",
"errorCreateContainer": "Failed to create container: {{error}}",
"errorImportData": "Failed to import data: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Anuluj",
"close": "Zamknij",
"save": "Zapisz",
"delete": "Usuń",
"update": "Aktualizuj",
"discard": "Odrzuć",
"execute": "Wykonaj",
"loading": "Ładowanie",
"loadingEllipsis": "Trwa ładowanie...",
"next": "Dalej",
"previous": "Wstecz",
"yes": "Tak",
"no": "Nie",
"result": "Wynik",
"learnMore": "Dowiedz się więcej",
"getStarted": "Wprowadzenie",
"retry": "Ponów próbę",
"apply": "Zastosuj",
"refresh": "Odśwież",
"copy": "Kopiuj",
"create": "Utwórz",
"confirm": "Potwierdź",
"open": "Otwarte",
"rename": "Zmień nazwę",
"download": "Pobierz",
"upload": "Przekaż",
"connect": "Połącz",
"remove": "Usuń",
"increaseValueBy1": "Zwiększ wartość o 1",
"decreaseValueBy1": "Zmniejsz wartość o 1"
},
"splashScreen": {
"title": {
"default": "Azure Cosmos DB — Zapraszamy!",
"postgres": "Azure Cosmos DB for PostgreSQL — Zapraszamy!",
"vcoreMongo": "Witamy w usłudze Azure DocumentDB (ze zgodnością z bazą danych MongoDB)"
},
"subtitle": {
"default": "Globalnie rozproszona, wielomodelowa usługa bazy danych na dowolną skalę",
"getStarted": "Rozpocznij pracę z naszymi przykładowymi zestawami danych, dokumentacją i dodatkowymi narzędziami."
},
"quickStart": {
"title": "Uruchom przewodnik Szybki start",
"description": "Uruchom samouczek Szybki start, aby rozpocząć pracę z przykładowymi danymi"
},
"newCollection": {
"title": "Nowy element {{collectionName}}",
"description": "Utwórz nowy kontener na potrzeby magazynu i przepływności"
},
"samplesGallery": {
"title": "Galeria przykładów usługi Azure Cosmos DB",
"description": "Odkryj przykłady przedstawiające skalowalne, inteligentne wzorce aplikacji. Wypróbuj ją teraz, aby zobaczyć, jak szybko możesz przejść od koncepcji do kodu za pomocą usługi Cosmos DB"
},
"connectCard": {
"title": "Połącz",
"description": "Wolisz korzystać z własnych narzędzi? Znajdź parametr połączenia potrzebny do nawiązania połączenia",
"pgAdmin": {
"title": "Nawiąż połączenie za pomocą narzędzia pgAdmin",
"description": "Wolisz pgAdmin? Tutaj znajdziesz parametry połączenia"
},
"vsCode": {
"title": "Nawiązywanie połączenia z edytorem VS Code",
"description": "Wykonuj zapytania dotyczące klastrów MongoDB i DocumentDB oraz zarządzaj nimi w programie Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "Powłoka PostgreSQL",
"description": "Utwórz tabelę i pracuj z danymi za pomocą powłoki interfejsu PostgreSQL"
},
"vcoreMongo": {
"title": "Powłoka Mongo",
"description": "Utwórz kolekcję i pracuj z danymi przy użyciu interfejsu powłoki bazy danych MongoDB"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "Jesteś nowym użytkownikiem usługi Cosmos DB PGSQL?",
"body": "Witaj! Jeśli dopiero zaczynasz pracę z Cosmos DB PGSQL i potrzebujesz pomocy przy rozpoczynaniu pracy, tutaj znajdziesz przykładowe dane i zapytania."
},
"resetPassword": {
"headline": "Utwórz hasło",
"body": "Jeśli hasło nie zostało jeszcze zmienione, zmień je teraz."
},
"coachMark": {
"headline": "Rozpocznij od przykładu {{collectionName}}",
"body": "Zostanie wyświetlony przewodnik, aby utworzyć przykładowy kontener z przykładowymi danymi, a następnie udostępnimy Ci przewodnik po eksploratorze danych. Możesz również anulować uruchamianie tego przewodnika i eksplorować siebie"
}
},
"sections": {
"recents": "Ostatnie",
"clearRecents": "Wyczyść ostatnie",
"top3": "3 najważniejsze rzeczy, które musisz wiedzieć",
"learningResources": "Zasoby szkoleniowe",
"nextSteps": "Następne kroki",
"tipsAndLearnMore": "Porady i dowiedz się więcej",
"notebook": "Notes",
"needHelp": "Potrzebujesz pomocy?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Zaawansowane wzorce modelowania",
"description": "Poznaj zaawansowane strategie optymalizowania bazy danych."
},
"partitioning": {
"title": "Najlepsze rozwiązania dotyczące partycjonowania",
"description": "Dowiedz się, jak stosować model danych i strategie partycjonowania."
},
"resourcePlanning": {
"title": "Planowanie wymagań dotyczących zasobów",
"description": "Poznaj różne opcje konfiguracji."
}
},
"mongo": {
"whatIsMongo": {
"title": "Co to jest interfejs API bazy danych MongoDB?",
"description": "Omówienie usługi Azure Cosmos DB dla bazy danych MongoDB i jej funkcji."
},
"features": {
"title": "Funkcje i składnia",
"description": "Odkryj zalety i funkcje"
},
"migrate": {
"title": "Migrowanie danych",
"description": "Kroki przed migracją na potrzeby przenoszenia danych"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Utwórz aplikację Java",
"description": "Utwórz aplikację Java przy użyciu zestawu SDK."
},
"partitioning": {
"title": "Najlepsze rozwiązania dotyczące partycjonowania",
"description": "Dowiedz się, jak działa partycjonowanie."
},
"requestUnits": {
"title": "Jednostki żądania (jednostki RU)",
"description": "Informacje o opłatach za jednostki RU."
}
},
"gremlin": {
"dataModeling": {
"title": "Modelowanie danych",
"description": "Zalecenia dotyczące modelowania danych programu Graph"
},
"partitioning": {
"title": "najlepszymi rozwiązaniami dotyczącymi partycjonowania",
"description": "Dowiedz się, jak działa partycjonowanie"
},
"queryData": {
"title": "Wykonaj zapytanie dotyczące danych",
"description": "Wykonywanie zapytań o dane przy użyciu języka Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "Co to jest interfejs API tabel?",
"description": "Omówienie usługi Azure Cosmos DB for Table i jej funkcji"
},
"migrate": {
"title": "Migrowanie danych",
"description": "Dowiedz się, jak migrować dane"
},
"faq": {
"title": "Azure Cosmos DB for Table — często zadawane pytania",
"description": "Typowe pytania dotyczące usługi Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Skróty klawiaturowe w Eksploratorze danych",
"description": "Poznaj skróty klawiaturowe umożliwiające nawigowanie w Eksploratorze danych."
},
"liveTv": {
"title": "Poznaj podstawy",
"description": "Obejrzyj wprowadzenie do programu telewizyjnego na żywo w usłudze Azure Cosmos DB i obejrzyj wideo."
},
"sql": {
"sdk": {
"title": "Wprowadzenie do korzystania z zestawu SDK",
"description": "Dowiedz się więcej o zestawie SDK usługi Azure Cosmos DB."
},
"migrate": {
"title": "Migrowanie danych",
"description": "Migruj dane przy użyciu usług platformy Azure i rozwiązań typu open source."
}
},
"mongo": {
"nodejs": {
"title": "Tworzenie aplikacji za pomocą Node.js",
"description": "Utwórz aplikację Node.js."
},
"gettingStarted": {
"title": "Przewodnik Wprowadzenie",
"description": "Zapoznaj się z podstawowymi informacjami dotyczącymi rozpoczynania pracy."
}
},
"cassandra": {
"createContainer": {
"title": "Utwórz kontener",
"description": "Zapoznaj się z opcjami tworzenia kontenera."
},
"throughput": {
"title": "Zaaprowizuj przepływność",
"description": "Dowiedz się, jak skonfigurować przepływność."
}
},
"gremlin": {
"getStarted": {
"title": "Wprowadzenie ",
"description": "Twórz, wykonuj zapytania i przechodź przy użyciu konsoli Gremlin"
},
"importData": {
"title": "Importuj dane wykresu",
"description": "Dowiedz się więcej o zbiorczym pozyskiwaniu danych przy użyciu narzędzia BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Utwórz aplikację platformy .NET",
"description": "Jak uzyskać dostęp do usługi Azure Cosmos DB for Table z poziomu aplikacji platformy .NET."
},
"java": {
"title": "Utwórz aplikację Java",
"description": "Utwórz aplikację usługi Azure Cosmos DB for Table przy użyciu zestawu Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Modelowanie danych",
"distributionColumn": "Jak wybrać kolumnę dystrybucji",
"buildApps": "Twórz aplikacje przy użyciu języka Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migruj dane",
"vectorSearch": "Twórz aplikacje AI za pomocą funkcji wyszukiwania wektorowego",
"buildApps": "Twórz aplikacje za pomocą środowiska Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Dostrajanie wydajności",
"diagnosticQueries": "Przydatne zapytania diagnostyczne",
"sqlReference": "Rozproszona dokumentacja SQL"
},
"vcoreMongo": {
"vectorSearch": "Wyszukiwanie wektorowe",
"textIndexing": "Indeksowanie tekstu",
"troubleshoot": "Rozwiązywanie typowych problemów"
}
},
"fabric": {
"buildTitle": "Utwórz bazę danych",
"useTitle": "Wykonaj „diff” dla swojej bazy danych",
"newContainer": {
"title": "Nowy kontener",
"description": "Utwórz kontener docelowy do przechowywania danych"
},
"sampleData": {
"title": "Dane przykładowe",
"description": "Załaduj przykładowe dane w bazie danych"
},
"sampleVectorData": {
"title": "Przykładowe dane wektorowe",
"description": "Załaduj przykładowe dane wektorowe za pomocą polecenia text-embedding-ada-002"
},
"appDevelopment": {
"title": "Opracowywanie aplikacji",
"description": "Zacznij tutaj, aby używać zestawu SDK do kompilowania aplikacji"
},
"sampleGallery": {
"title": "Galeria przykładów",
"description": "Uzyskaj rzeczywiste, kompleksowe przykłady"
}
},
"sampleDataDialog": {
"title": "Dane przykładowe",
"startButton": "Start",
"createPrompt": "Utwórz kontener „{{containerName}}” i zaimportuj do niego przykładowe dane. Może to potrwać kilka minut.",
"creatingContainer": "Tworzenie kontenera „{{containerName}}”...",
"importingData": "Trwa importowanie danych do folderu „{{containerName}}”...",
"success": "Pomyślnie utworzono „{{containerName}}” z przykładowymi danymi.",
"errorContainerExists": "Kontener „{{containerName}}” w bazie danych „{{databaseName}}” już istnieje. Usuń go i spróbuj ponownie.",
"errorCreateContainer": "Nie można utworzyć kontenera: {{error}}",
"errorImportData": "Nie można zaimportować danych: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Cancelar",
"close": "Fechar",
"save": "Salvar",
"delete": "Excluir",
"update": "Atualizar",
"discard": "Descartar",
"execute": "Executar",
"loading": "Carregando",
"loadingEllipsis": "Carregando...",
"next": "Avançar",
"previous": "Anterior",
"yes": "Sim",
"no": "Não",
"result": "Resultado",
"learnMore": "Saiba mais",
"getStarted": "Introdução",
"retry": "Repetir",
"apply": "Aplicar",
"refresh": "Atualizar",
"copy": "Copiar",
"create": "Criar",
"confirm": "Confirmar",
"open": "Aberto",
"rename": "Renomear",
"download": "Baixar",
"upload": "Carregar",
"connect": "Conectar",
"remove": "Remover",
"increaseValueBy1": "Aumentar o valor em 1",
"decreaseValueBy1": "Diminuir valor em 1"
},
"splashScreen": {
"title": {
"default": "Bem-vindo ao Azure Cosmos DB",
"postgres": "Bem-vindo ao Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Bem-vindo ao Azure DocumentDB (com compatibilidade com MongoDB)"
},
"subtitle": {
"default": "Serviço de multimodelo de banco de dados globalmente distribuído para qualquer escala",
"getStarted": "Comece com nossos conjuntos de dados de exemplo, documentação e ferramentas adicionais."
},
"quickStart": {
"title": "Iniciar o início rápido",
"description": "Iniciar um tutorial de início rápido para começar a usar os dados de exemplo"
},
"newCollection": {
"title": "Novo {{collectionName}}",
"description": "Crie um novo contêiner para armazenamento e taxa de transferência"
},
"samplesGallery": {
"title": "Galeria de exemplos do Azure Cosmos DB",
"description": "Descubra exemplos que demonstram padrões de aplicativos inteligentes e escalonáveis. Experimente um agora para ver a rapidez com que você pode passar do conceito para o código com o Cosmos DB"
},
"connectCard": {
"title": "Conectar",
"description": "Prefere usar suas próprias ferramentas? Localize a cadeia de conexão que você precisa para conectar",
"pgAdmin": {
"title": "Conectar com o pgAdmin",
"description": "Prefere pgAdmin? Encontre suas cadeias de conexão aqui"
},
"vsCode": {
"title": "Conectar-se com o VS Code",
"description": "Consultar e gerenciar seus clusters do MongoDB e do DocumentDB no Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "Shell do PostgreSQL",
"description": "Criar tabela e interagir com dados usando a interface de shell do PostgreSQL"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Criar uma coleção e interagir com os dados usando a interface de shell do MongoDB"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "Novo no Cosmos DB PGSQL?",
"body": "Bem-vindo(a)! Se você é novo no Cosmos DB PGSQL e precisa de ajuda para começar, aqui é onde você pode encontrar dados de exemplo e consultas."
},
"resetPassword": {
"headline": "Criar a sua senha",
"body": "Se você ainda não alterou sua senha, altere-a agora."
},
"coachMark": {
"headline": "Comece com o exemplo {{collectionName}}",
"body": "Você será guiado a criar um contêiner de exemplo com dados de exemplo e, em seguida, faremos um tour pelo Data Explorer. Você também pode cancelar o tour e explorar por conta própria"
}
},
"sections": {
"recents": "Recentes",
"clearRecents": "Limpar Recentes",
"top3": "As três principais coisas que você precisa saber",
"learningResources": "Recursos de aprendizado",
"nextSteps": "Próximas etapas",
"tipsAndLearnMore": "Dicas e saiba mais",
"notebook": "Notebook",
"needHelp": "Precisa de ajuda?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Padrões avançados de modelagem",
"description": "Aprenda estratégias avançadas para otimizar seu banco de dados."
},
"partitioning": {
"title": "Melhores práticas de particionamento",
"description": "Aprenda a aplicar estratégias de particionamento e modelo de dados."
},
"resourcePlanning": {
"title": "Planejar seus requisitos de recursos",
"description": "Conheça as diferentes opções de configuração."
}
},
"mongo": {
"whatIsMongo": {
"title": "O que é a API do MongoDB?",
"description": "Entenda o Azure Cosmos DB for MongoDB e seus recursos."
},
"features": {
"title": "Recursos e sintaxe",
"description": "Descubra as vantagens e os recursos"
},
"migrate": {
"title": "Migrar seus dados",
"description": "Etapas de pré-migração para mover dados"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Criar um aplicativo Java",
"description": "Crie um aplicativo Java usando um SDK."
},
"partitioning": {
"title": "Melhores práticas de particionamento",
"description": "Saiba como funciona o particionamento."
},
"requestUnits": {
"title": "RUs (Unidades de Solicitação)",
"description": "Entenda os encargos de RU."
}
},
"gremlin": {
"dataModeling": {
"title": "Modelagem de Dados",
"description": "Recomendações de modelagem de dados do Graph"
},
"partitioning": {
"title": "Melhores práticas de particionamento",
"description": "Saiba como funciona o particionamento"
},
"queryData": {
"title": "Consultar dados",
"description": "Consultando dados com Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "Qual é o API de Tabela?",
"description": "Entenda o Azure Cosmos DB for Table e seus recursos"
},
"migrate": {
"title": "Migrar seus dados",
"description": "Saiba como migrar seus dados"
},
"faq": {
"title": "Perguntas frequentes do Azure Cosmos DB for Table",
"description": "Perguntas comuns sobre o Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Atalhos de teclado do Data Explorer",
"description": "Aprenda atalhos de teclado para navegar no Data Explorer."
},
"liveTv": {
"title": "Aprender os Conceitos Básicos",
"description": "Assista aos vídeos introdutórios e tutoriais do programa de TV ao vivo do Azure Cosmos DB."
},
"sql": {
"sdk": {
"title": "Introdução ao uso de um SDK",
"description": "Saiba mais sobre o SDK do Azure Cosmos DB."
},
"migrate": {
"title": "Migrar seus dados",
"description": "Migre dados usando serviços do Azure e soluções de código aberto."
}
},
"mongo": {
"nodejs": {
"title": "Criar um aplicativo com Node.js",
"description": "Crie um aplicativo Node.js."
},
"gettingStarted": {
"title": "Guia de Introdução",
"description": "Aprenda as noções básicas para começar."
}
},
"cassandra": {
"createContainer": {
"title": "Criar um Contêiner",
"description": "Conheça as opções de criação de um contêiner."
},
"throughput": {
"title": "Provisionar Taxa de Transferência",
"description": "Saiba como configurar a taxa de transferência."
}
},
"gremlin": {
"getStarted": {
"title": "Introdução ",
"description": "Crie, consulte e navegue usando o console do Gremlin"
},
"importData": {
"title": "Importar Dados do Graph",
"description": "Aprenda sobre ingestão em massa usando o BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Criar um aplicativo .NET",
"description": "Como acessar o Azure Cosmos DB for Table a partir de um aplicativo .NET."
},
"java": {
"title": "Criar um aplicativo Java",
"description": "Crie um aplicativo Azure Cosmos DB for Table com o SDK Java "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Modelagem de Dados",
"distributionColumn": "Como escolher uma Coluna de Distribuição",
"buildApps": "Criar aplicativos com Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrar Dados",
"vectorSearch": "Crie aplicativos de IA com Busca em vetores",
"buildApps": "Criar aplicativos com Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Ajuste de Desempenho",
"diagnosticQueries": "Consultas úteis para diagnóstico",
"sqlReference": "Referência de SQL distribuído"
},
"vcoreMongo": {
"vectorSearch": "Busca em Vetores",
"textIndexing": "Indexação de Texto",
"troubleshoot": "Solucionar problemas comuns"
}
},
"fabric": {
"buildTitle": "Criar seu banco de dados",
"useTitle": "Usar seu banco de dados",
"newContainer": {
"title": "Novo contêiner",
"description": "Criar um contêiner de destino para armazenar seus dados"
},
"sampleData": {
"title": "Dados de Exemplo",
"description": "Carregar dados de exemplo em seu banco de dados"
},
"sampleVectorData": {
"title": "Dados vetoriais de exemplo",
"description": "Carregar dados vetoriais de exemplo com text-embedding-ada-002"
},
"appDevelopment": {
"title": "Desenvolvimento de aplicativos",
"description": "Comece aqui para usar um SDK para criar seus aplicativos"
},
"sampleGallery": {
"title": "Galeria de exemplos",
"description": "Obtenha exemplos completos do mundo real"
}
},
"sampleDataDialog": {
"title": "Dados de Exemplo",
"startButton": "Iniciar",
"createPrompt": "Crie um contêiner \"{{containerName}}\" e importe dados de exemplo para ele. Isso pode levar alguns minutos.",
"creatingContainer": "Criando contêiner \"{{containerName}}\"...",
"importingData": "Importando dados para \"{{containerName}}\"...",
"success": "\"{{containerName}}\" criado com sucesso com dados de exemplo.",
"errorContainerExists": "O contêiner \"{{containerName}}\" no banco de dados \"{{databaseName}}\" já existe. Exclua-o e tente novamente.",
"errorCreateContainer": "Falha ao criar o contêiner: {{error}}",
"errorImportData": "Falha ao importar dados: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Cancelar",
"close": "Fechar",
"save": "Guardar",
"delete": "Eliminar",
"update": "Atualizar",
"discard": "Eliminar",
"execute": "Executar",
"loading": "A carregar",
"loadingEllipsis": "A carregar...",
"next": "Seguinte",
"previous": "Anterior",
"yes": "Sim",
"no": "Não",
"result": "Resultado",
"learnMore": "Saber mais",
"getStarted": "Começar",
"retry": "Tentar novamente",
"apply": "Aplicar",
"refresh": "Atualizar",
"copy": "Copiar",
"create": "Criar",
"confirm": "Confirmar",
"open": "Abrir",
"rename": "Mudar o Nome",
"download": "Transferir",
"upload": "Carregar",
"connect": "Ligar",
"remove": "Remover",
"increaseValueBy1": "Aumentar valor em 1",
"decreaseValueBy1": "Diminuir valor em 1"
},
"splashScreen": {
"title": {
"default": "Bem-vindo ao Azure Cosmos DB",
"postgres": "Bem-vindo ao Azure Cosmos DB para PostgreSQL",
"vcoreMongo": "Bem-vindo ao Azure DocumentDB (com compatibilidade do MongoDB)"
},
"subtitle": {
"default": "Serviço de base de dados com múltiplos modelos distribuído globalmente para qualquer dimensionamento",
"getStarted": "Comece a trabalhar com os nossos conjuntos de dados de exemplo, documentação e ferramentas adicionais."
},
"quickStart": {
"title": "Iniciar início rápido",
"description": "Inicie um tutorial de início rápido para começar a utilizar dados de exemplo"
},
"newCollection": {
"title": "Novo {{collectionName}}",
"description": "Criar um novo contentor para armazenamento e débito"
},
"samplesGallery": {
"title": "Galeria de Exemplos do Azure Cosmos DB",
"description": "Descubra exemplos que apresentam padrões de aplicações escaláveis e inteligentes. Experimente um agora para ver a rapidez com que pode passar do conceito ao código com o Cosmos DB"
},
"connectCard": {
"title": "Ligar",
"description": "Prefere usar as suas próprias ferramentas? Encontre a cadeia de ligação de que precisa para comunicar",
"pgAdmin": {
"title": "Comunicar com o pgAdmin",
"description": "Prefere o pgAdmin? Encontre as suas cadeias de ligação aqui"
},
"vsCode": {
"title": "Ligar ao VS Code",
"description": "Consulte e gerencie seus clusters MongoDB e DocumentDB no Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Criar uma tabela e interagir com dados usando a interface shell do PostgreSQL"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Criar uma coleção e interagir com dados usando a interface shell do MongoDB"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "Novo no Cosmos DB PGSQL?",
"body": "Damos-lhe as boas-vindas! Se é novo no Cosmos DB PGSQL e precisa de ajuda para começar, aqui pode encontrar dados de exemplo e consultas."
},
"resetPassword": {
"headline": "Criar a sua palavra-passe",
"body": "Se ainda não alterou a sua palavra-passe, altere-a agora."
},
"coachMark": {
"headline": "Começar com amostra {{collectionName}}",
"body": "Será orientado para criar um contentor de exemplo com dados de exemplo e, em seguida, faremos uma visita guiada ao explorador de dados. Também pode cancelar o lançamento desta visita e explorar por si próprio."
}
},
"sections": {
"recents": "Recentes",
"clearRecents": "Limpar recentes",
"top3": "As três principais coisas que precisa de saber",
"learningResources": "Recursos de Aprendizagem",
"nextSteps": "Passos seguintes",
"tipsAndLearnMore": "Sugestões e saiba mais",
"notebook": "Bloco de notas",
"needHelp": "Precisa de ajuda?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Padrões Avançados de Modelação",
"description": "Aprenda estratégias avançadas para otimizar a sua base de dados."
},
"partitioning": {
"title": "Melhores práticas para a criação de partições",
"description": "Aprenda a aplicar o modelo de dados e as estratégias de partição."
},
"resourcePlanning": {
"title": "Planear os seus Requisitos de Recursos",
"description": "Conheça as diferentes opções de configuração."
}
},
"mongo": {
"whatIsMongo": {
"title": "O que é a API MongoDB?",
"description": "Compreenda o Azure Cosmos DB for MongoDB e as suas funcionalidades."
},
"features": {
"title": "Funcionalidades e Sintaxe",
"description": "Descubra as vantagens e funcionalidades"
},
"migrate": {
"title": "Migrar os seus dados",
"description": "Passos de pré-migração para fazer a migração de dados"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Criar uma Aplicação Java",
"description": "Crie uma aplicação Java com um SDK."
},
"partitioning": {
"title": "Melhores práticas para a criação de partições",
"description": "Saiba como funciona a partição."
},
"requestUnits": {
"title": "Unidades de Pedido (RUs)",
"description": "Compreenda as cobranças de RU."
}
},
"gremlin": {
"dataModeling": {
"title": "Modelação de dados",
"description": "Recomendações para modelação de dados do Graph"
},
"partitioning": {
"title": "Melhores práticas para a criação de partições",
"description": "Saiba como funciona a partição"
},
"queryData": {
"title": "Consultar dados",
"description": "Consultar dados com o Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "O que é a API Table?",
"description": "Compreenda o Azure Cosmos DB for Table e as suas funcionalidades"
},
"migrate": {
"title": "Migrar os seus dados",
"description": "Saiba como migrar dados"
},
"faq": {
"title": "Azure Cosmos DB for Table FAQs",
"description": "Perguntas comuns sobre o Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Atalhos de teclado do Data Explorer",
"description": "Aprenda atalhos de teclado para navegar no Data Explorer."
},
"liveTv": {
"title": "Aprenda as Noções Básicas",
"description": "Veja o programa de TV em direto do Azure Cosmos DB e vídeos de introdução e tutoriais."
},
"sql": {
"sdk": {
"title": "Começar a utilizar um SDK",
"description": "Saiba mais sobre o Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrar os seus dados",
"description": "Migre dados utilizando serviços Azure e soluções open-source."
}
},
"mongo": {
"nodejs": {
"title": "Criar uma aplicação com Node.js",
"description": "Criar uma aplicação Node.js."
},
"gettingStarted": {
"title": "Guia de Introdução",
"description": "Aprenda o básico para começar."
}
},
"cassandra": {
"createContainer": {
"title": "Criar um Contentor",
"description": "Conheça as opções para criar um contentor."
},
"throughput": {
"title": "Débito de Aprovisionamento",
"description": "Saiba como configurar o débito."
}
},
"gremlin": {
"getStarted": {
"title": "Começar a Utilizar ",
"description": "Criar, consultar e percorrer utilizando a consola Gremlin"
},
"importData": {
"title": "Importar Dados do Grafo",
"description": "Saiba como fazer a ingestão em massa de dados com o BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Criar uma Aplicação .NET",
"description": "Como aceder ao Azure Cosmos DB for Table a partir de uma aplicação .NET."
},
"java": {
"title": "Criar uma Aplicação Java",
"description": "Crie uma aplicação Azure Cosmos DB for Table com o Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Modelação de dados",
"distributionColumn": "Como escolher uma Coluna de Distribuição",
"buildApps": "Criar Aplicações com Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrar dados",
"vectorSearch": "Criar aplicações de IA com a Pesquisa de Vectores",
"buildApps": "Criar Aplicações com Node.js"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Ajuste do Desempenho",
"diagnosticQueries": "Consultas de Diagnóstico Úteis",
"sqlReference": "Referência de SQL Distribuído"
},
"vcoreMongo": {
"vectorSearch": "Pesquisa de Vectores",
"textIndexing": "Indexação de Texto",
"troubleshoot": "Resolver problemas comuns"
}
},
"fabric": {
"buildTitle": "Crie a sua base de dados",
"useTitle": "Utilizar a sua base de dados",
"newContainer": {
"title": "Novo contentor",
"description": "Crie um contentor de destino para armazenar os seus dados"
},
"sampleData": {
"title": "Dados de Amostra",
"description": "Carregar dados de exemplo na sua base de dados"
},
"sampleVectorData": {
"title": "Dados Vetoriais de Exemplo",
"description": "Carregar dados de vetor de exemplo com text-embedding-ada-002"
},
"appDevelopment": {
"title": "Desenvolvimento de aplicações",
"description": "Comece aqui para utilizar um SDK para criar as suas aplicações"
},
"sampleGallery": {
"title": "Galeria de Exemplos",
"description": "Obter exemplos completos do mundo real"
}
},
"sampleDataDialog": {
"title": "Dados de Amostra",
"startButton": "Início",
"createPrompt": "Crie um contentor \"{{containerName}}\" e importe dados de exemplo para o mesmo. Esta operação pode demorar alguns minutos.",
"creatingContainer": "A criar o contentor \"{{containerName}}\"...",
"importingData": "A importar dados para \"{{containerName}}\"...",
"success": "\"{{containerName}}\" criado com êxito com dados de exemplo.",
"errorContainerExists": "O contentor \"{{containerName}}\" na base de dados \"{{databaseName}}\" já existe. Elimine-o e tente novamente.",
"errorCreateContainer": "Falha ao criar o contentor: {{error}}",
"errorImportData": "Falha ao importar dados: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "ОК",
"cancel": "Отмена",
"close": "Закрыть",
"save": "Сохранить",
"delete": "Удалить",
"update": "Обновить",
"discard": "Отменить",
"execute": "Выполнить",
"loading": "Загрузка",
"loadingEllipsis": "Идет загрузка…",
"next": "Далее",
"previous": "Назад",
"yes": "Да",
"no": "Нет",
"result": "Результат",
"learnMore": "Подробнее",
"getStarted": "Начало работы",
"retry": "Повторить",
"apply": "Применить",
"refresh": "Обновить",
"copy": "Копировать",
"create": "Создать",
"confirm": "Подтвердить",
"open": "Открыть",
"rename": "Переименовать",
"download": "Скачать",
"upload": "Отправить",
"connect": "Подключить",
"remove": "Удалить",
"increaseValueBy1": "Увеличить значение на 1",
"decreaseValueBy1": "Уменьшить значение на 1"
},
"splashScreen": {
"title": {
"default": "Вас приветствует Azure Cosmos DB",
"postgres": "Добро пожаловать в Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Добро пожаловать в Azure DocumentDB (с совместимостью с MongoDB)"
},
"subtitle": {
"default": "Глобально распределенная многомодельная служба базы данных для использования в любом масштабе",
"getStarted": "Начните работу с нашими примерами наборов данных, документацией и дополнительными инструментами."
},
"quickStart": {
"title": "Начать быстрый запуск",
"description": "Запустите краткое обучающее руководство, чтобы начать работу с примерами данных"
},
"newCollection": {
"title": "Новый {{collectionName}}",
"description": "Создайте новый контейнер для хранения данных и обеспечения пропускной способности"
},
"samplesGallery": {
"title": "Галерея примеров Azure Cosmos DB",
"description": "Ознакомьтесь с примерами, демонстрирующими масштабируемые и интеллектуальные шаблоны приложений. Попробуйте прямо сейчас и убедитесь, как быстро вы можете перейти от концепции к коду с Cosmos DB"
},
"connectCard": {
"title": "Подключить",
"description": "Предпочитаете использовать собственные инструменты? Найдите строку подключения, необходимую для соединения.",
"pgAdmin": {
"title": "Свяжитесь с pgAdmin",
"description": "Предпочитаете pgAdmin? Здесь вы найдете строки подключения"
},
"vsCode": {
"title": "Подключиться к VS Code",
"description": "Запрашивайте данные и управляйте кластерами MongoDB и DocumentDB в Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "Оболочка PostgreSQL",
"description": "Создайте таблицу и взаимодействуйте с данными, используя командный интерфейс PostgreSQL"
},
"vcoreMongo": {
"title": "Оболочка Mongo",
"description": "Создайте коллекцию и взаимодействуйте с данными, используя командный интерфейс MongoDB"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "Впервые работаете с Cosmos DB PGSQL?",
"body": "Добро пожаловать! Если вы новичок в Cosmos DB PGSQL и вам нужна помощь в начале работы, здесь вы можете найти примеры данных и запросов."
},
"resetPassword": {
"headline": "Создайте пароль",
"body": "Если вы еще не сменили пароль, сделайте это прямо сейчас."
},
"coachMark": {
"headline": "Начнём с образца {{collectionName}}",
"body": "Вам будет предложено создать тестовый контейнер с тестовыми данными, после чего мы проведем для вас ознакомительный обзор инструмента \"Обозреватель данных\". Вы также можете отменить запуск этого тура и исследовать местность самостоятельно"
}
},
"sections": {
"recents": "Последние",
"clearRecents": "Очистить последние",
"top3": "Три главных вещи, которые вам нужно знать",
"learningResources": "Учебные материалы",
"nextSteps": "Дальнейшие действия",
"tipsAndLearnMore": "Советы и дополнительная информация",
"notebook": "Записная книжка",
"needHelp": "Нужна помощь?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Расширенные шаблоны моделирования",
"description": "Изучите передовые стратегии оптимизации вашей базы данных."
},
"partitioning": {
"title": "Передовые методы разделения данных",
"description": "Научитесь применять стратегии моделирования данных и их разделения на разделы."
},
"resourcePlanning": {
"title": "Спланируйте свои потребности в ресурсах",
"description": "Ознакомьтесь с различными вариантами конфигурации."
}
},
"mongo": {
"whatIsMongo": {
"title": "Что такое API MongoDB?",
"description": "Разберитесь в Azure Cosmos DB для MongoDB и его возможностях."
},
"features": {
"title": "Особенности и синтаксис",
"description": "Узнайте о преимуществах и особенностях"
},
"migrate": {
"title": "Перенесите свои данные",
"description": "Этапы подготовки к миграции данных"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Создайте Java-приложение",
"description": "Создайте Java-приложение, используя SDK."
},
"partitioning": {
"title": "Передовые методы разделения данных",
"description": "Узнайте, как работает разбиение на разделы."
},
"requestUnits": {
"title": "Единицы запроса (ЕЗ)",
"description": "Разберитесь в тарифах RU."
}
},
"gremlin": {
"dataModeling": {
"title": "Моделирование данных",
"description": "Рекомендации по моделированию графовых данных"
},
"partitioning": {
"title": "Передовые методы разделения данных",
"description": "Узнайте, как работает разбиение на разделы"
},
"queryData": {
"title": "Запрос данных",
"description": "Запросы к данным с помощью Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "Что такое API таблиц?",
"description": "Разберитесь в Azure Cosmos DB for Table и его возможностях"
},
"migrate": {
"title": "Перенесите свои данные",
"description": "Сведения о миграции данных"
},
"faq": {
"title": "Часто задаваемые вопросы об Azure Cosmos DB для таблиц",
"description": "Часто задаваемые вопросы об Azure Cosmos DB для таблиц"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Клавиатурные сочетания в Data Explorer",
"description": "Изучите сочетания клавиш для навигации по обозревателю данных."
},
"liveTv": {
"title": "Изучение основ",
"description": "Смотрите вводные и обучающие видеоролики о Azure Cosmos DB Live TV."
},
"sql": {
"sdk": {
"title": "Начните работу с SDK",
"description": "Узнайте больше об SDK Azure Cosmos DB."
},
"migrate": {
"title": "Перенесите свои данные",
"description": "Перенесите данные, используя службы Azure и решения с открытым исходным кодом."
}
},
"mongo": {
"nodejs": {
"title": "Создайте приложение с помощью Node.js",
"description": "Создайте приложение Node.js."
},
"gettingStarted": {
"title": "Руководство по началу работы",
"description": "Изучите основы, чтобы начать."
}
},
"cassandra": {
"createContainer": {
"title": "Создать контейнер",
"description": "Ознакомьтесь с параметрами создания контейнера."
},
"throughput": {
"title": "Пропускная способность предоставления",
"description": "Узнайте, как настроить пропускную способность."
}
},
"gremlin": {
"getStarted": {
"title": "Начать ",
"description": "Создавайте, запрашивайте и обходите данные с помощью консоли Gremlin"
},
"importData": {
"title": "Импорт графических данных",
"description": "Узнайте, как осуществлять массовую загрузку данных с помощью BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Создайте приложение на платформе .NET",
"description": "Как получить доступ к Azure Cosmos DB for Table из приложения .NET."
},
"java": {
"title": "Создайте Java-приложение",
"description": "Создайте приложение Azure Cosmos DB for Table с помощью Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Моделирование данных",
"distributionColumn": "Как выбрать столбец распределения",
"buildApps": "Создавайте приложения с помощью Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Перенести данные",
"vectorSearch": "Создавайте приложения с искусственным интеллектом с помощью Vector Search",
"buildApps": "Создавайте приложения с помощью Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Настройка производительности",
"diagnosticQueries": "Полезные диагностические запросы",
"sqlReference": "Справочник по распределенному SQL"
},
"vcoreMongo": {
"vectorSearch": "Поиск векторов",
"textIndexing": "Индексирование текста",
"troubleshoot": "Устранение распространенных неполадок"
}
},
"fabric": {
"buildTitle": "Создание базы данных",
"useTitle": "Используйте свою базу данных",
"newContainer": {
"title": "Новый контейнер",
"description": "Создайте целевой контейнер для хранения ваших данных"
},
"sampleData": {
"title": "Пример данных",
"description": "Загрузите примеры данных в свою базу данных"
},
"sampleVectorData": {
"title": "Пример векторных данных",
"description": "Загрузите примеры векторных данных с помощью text-embedding-ada-002"
},
"appDevelopment": {
"title": "Разработка приложений",
"description": "Начните здесь, чтобы использовать SDK для создания своих приложений"
},
"sampleGallery": {
"title": "Образцы галереи",
"description": "Получите реальные примеры комплексного решения"
}
},
"sampleDataDialog": {
"title": "Пример данных",
"startButton": "Начать",
"createPrompt": "Создайте контейнер \" {{containerName}} \" и импортируйте в него примерные данные. Это может занять несколько минут.",
"creatingContainer": "Создание контейнера \" {{containerName}} \"...",
"importingData": "Импорт данных в \" {{containerName}} \"...",
"success": "Успешно создан \" {{containerName}} \" с примерами данных.",
"errorContainerExists": "Контейнер \" {{containerName}} \" в базе данных \" {{databaseName}} \" уже существует. Удалите его и попробуйте снова.",
"errorCreateContainer": "Не удалось создать контейнер: {{error}}",
"errorImportData": "Не удалось импортировать данные: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "OK",
"cancel": "Avbryt",
"close": "Stäng",
"save": "Spara",
"delete": "Ta bort",
"update": "Uppdatera",
"discard": "Ta bort",
"execute": "Kör",
"loading": "Läser in",
"loadingEllipsis": "Läser in...",
"next": "Nästa",
"previous": "Föregående",
"yes": "Ja",
"no": "Nej",
"result": "Resultat",
"learnMore": "Mer information",
"getStarted": "Kom igång",
"retry": "Försök igen",
"apply": "Använd",
"refresh": "Uppdatera",
"copy": "Kopiera",
"create": "Skapa",
"confirm": "Bekräfta",
"open": "Öppna",
"rename": "Byt namn",
"download": "Ladda ned",
"upload": "Ladda upp",
"connect": "Anslut",
"remove": "Ta bort",
"increaseValueBy1": "Öka värdet med 1",
"decreaseValueBy1": "Minska värdet med 1"
},
"splashScreen": {
"title": {
"default": "Välkommen till Azure Cosmos DB",
"postgres": "Välkommen till Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "Välkommen till Azure DocumentDB (med MongoDB-kompatibilitet)"
},
"subtitle": {
"default": "Globalt distribuerad databas för flera datamodeller oavsett skala",
"getStarted": "Kom igång med våra exempeldatamängder, dokumentation och extra verktyg."
},
"quickStart": {
"title": "Starta snabbstart",
"description": "Starta en snabbstartsguide för att komma igång med exempeldata"
},
"newCollection": {
"title": "Ny {{collectionName}}",
"description": "Skapa en ny container för lagring och dataflöde"
},
"samplesGallery": {
"title": "Galleri för Azure Cosmos DB-exempel",
"description": "Upptäck exempel som visar skalbara, intelligenta appmönster. Prova en nu för att se hur snabbt du kan gå från koncept till kod med Cosmos DB"
},
"connectCard": {
"title": "Anslut",
"description": "Föredrar du att använda ditt eget val av verktyg? Hitta anslutningssträngen du behöver för att ansluta",
"pgAdmin": {
"title": "Anslut med pgAdmin",
"description": "Föredrar du pgAdmin? Hitta dina anslutningssträngar här"
},
"vsCode": {
"title": "Anslut med VS Code",
"description": "Fråga och hantera dina MongoDB- och DocumentDB-kluster i Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL-gränssnitt",
"description": "Skapa tabell och interagera med data med postgreSQL-gränssnittet"
},
"vcoreMongo": {
"title": "Mongo-gränssnitt",
"description": "Skapa en samling och interagera med data med hjälp av MongoDB:s gränssnitt"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "Är Cosmos DB PGSQL nytt för dig?",
"body": "Välkommen! Om du är nybörjare på Cosmos DB PGSQL och behöver hjälp med att komma igång hittar du exempeldata och frågor här."
},
"resetPassword": {
"headline": "Skapa ett lösenord",
"body": "Om du inte har ändrat ditt lösenord ännu ändrar du det nu."
},
"coachMark": {
"headline": "Börja med exempel {{collectionName}}",
"body": "Du får vägledning för att skapa en exempelcontainer med exempeldata, och sedan får du en rundtur i datautforskaren. Du kan också avbryta lanseringen av den här rundturen och utforska dig själv"
}
},
"sections": {
"recents": "Senaste",
"clearRecents": "Rensa senaste",
"top3": "De 3 viktigaste sakerna du behöver veta",
"learningResources": "Utbildningsresurser",
"nextSteps": "Nästa steg",
"tipsAndLearnMore": "Tips och läs mer",
"notebook": "Anteckningsbok",
"needHelp": "Behöver du hjälp?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Avancerade modelleringsmönster",
"description": "Lär dig avancerade strategier för att optimera din databas."
},
"partitioning": {
"title": "Metodtipsen för partitionering",
"description": "Lär dig hur du tillämpar strategier för datamodeller och partitionering."
},
"resourcePlanning": {
"title": "Planera dina resurskrav",
"description": "Lär känna de olika konfigurationsalternativen."
}
},
"mongo": {
"whatIsMongo": {
"title": "Vad är MongoDB-API:et?",
"description": "Förstå Azure Cosmos DB for MongoDB och dess funktioner."
},
"features": {
"title": "Funktioner och syntax",
"description": "Upptäck fördelarna och funktionerna"
},
"migrate": {
"title": "Migrera dina data",
"description": "Steg före migrering för att flytta data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Skapa en Java-app",
"description": "Skapa en Java-app med hjälp av en SDK."
},
"partitioning": {
"title": "Metodtipsen för partitionering",
"description": "Lär dig hur partitionering fungerar."
},
"requestUnits": {
"title": "Enheter för programbegäran (RU)",
"description": "Förstå RU-avgifter."
}
},
"gremlin": {
"dataModeling": {
"title": "Datamodellering",
"description": "Rekommendationer för diagramdatamodellering"
},
"partitioning": {
"title": "Metodtipsen för partitionering",
"description": "Lär dig hur partitionering fungerar"
},
"queryData": {
"title": "Efterfråga data",
"description": "Köra frågor mot data med Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "Vad är Table API?",
"description": "Förstå Azure Cosmos DB for Table och dess funktioner"
},
"migrate": {
"title": "Migrera dina data",
"description": "Läs hur du migrerar dina data"
},
"faq": {
"title": "Vanliga frågor och svar om Azure Cosmos DB for Table",
"description": "Vanliga frågor om Azure Cosmos DB för tabell"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Datautforskaren kortkommandon",
"description": "Lär dig kortkommandon för att navigera Datautforskaren."
},
"liveTv": {
"title": "Lär dig grunderna",
"description": "Titta på Azure Cosmos DB introduktion till live-TV-program och hur du gör videor."
},
"sql": {
"sdk": {
"title": "Kom igång med ett SDK",
"description": "Läs mer om Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrera dina data",
"description": "Migrera data med Hjälp av Azure-tjänster och lösningar med öppen källkod."
}
},
"mongo": {
"nodejs": {
"title": "Skapa en app med Node.js",
"description": "Skapa en Node.js app."
},
"gettingStarted": {
"title": "Komma igång-guide",
"description": "Lär dig grunderna för att komma igång."
}
},
"cassandra": {
"createContainer": {
"title": "Skapa en container",
"description": "Lär känna alternativen för att skapa en container."
},
"throughput": {
"title": "Etablera dataflöde",
"description": "Lär dig hur du konfigurerar dataflöde."
}
},
"gremlin": {
"getStarted": {
"title": "Kom igång ",
"description": "Skapa, fråga och bläddra med Gremlin-konsolen"
},
"importData": {
"title": "Importera diagramdata",
"description": "Lär dig massinmatning av data med BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Skapa en .NET-app",
"description": "Så här kommer du åt Azure Cosmos DB for Table från en .NET-app."
},
"java": {
"title": "Skapa en Java-app",
"description": "Skapa en Azure Cosmos DB for Table-appen med Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Datamodellering",
"distributionColumn": "Så här väljer du en distributionskolumn",
"buildApps": "Skapa appar med Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrera data",
"vectorSearch": "Skapa AI-appar med Vector Search",
"buildApps": "Skapa appar med Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Prestandajustering",
"diagnosticQueries": "Användbara diagnostikfrågor",
"sqlReference": "Distribuerad SQL-referens"
},
"vcoreMongo": {
"vectorSearch": "Vektorssökning",
"textIndexing": "Textindexering",
"troubleshoot": "Felsök vanliga problem"
}
},
"fabric": {
"buildTitle": "Skapa din databas",
"useTitle": "Använda databasen",
"newContainer": {
"title": "Ny container",
"description": "Skapa en målcontainer för att lagra dina data"
},
"sampleData": {
"title": "Exempeldata",
"description": "Läs in exempeldata i databasen"
},
"sampleVectorData": {
"title": "Exempelvektordata",
"description": "Läs in exempelvektordata med textinbäddning-ada-002"
},
"appDevelopment": {
"title": "Apputveckling",
"description": "Börja här om du vill använda en SDK för att skapa dina appar"
},
"sampleGallery": {
"title": "Exempelgalleri",
"description": "Få verkliga exempel från slutpunkt till slutpunkt"
}
},
"sampleDataDialog": {
"title": "Exempeldata",
"startButton": "Starta",
"createPrompt": "Skapa en container \"{{containerName}}\" och importera exempeldata till den. Det här kan ta några minuter.",
"creatingContainer": "Skapar container \"{{containerName}}\"...",
"importingData": "Importerar data till \"{{containerName}}\"...",
"success": "\"{{containerName}}\" med exempeldata har skapats.",
"errorContainerExists": "Containern \"{{containerName}}\" i databasen \"{{databaseName}}\" finns redan. Ta bort den och försök igen.",
"errorCreateContainer": "Det gick inte att skapa containern: {{error}}",
"errorImportData": "Det gick inte att importera data: {{error}}"
}
}
}

View File

@@ -1,24 +0,0 @@
import i18n from "../i18n";
import type enResources from "./en/Resources.json";
/**
* Derives a union of all dot-notation key paths from a nested JSON object type.
* e.g. { buttons: { save: "Save" } } → "buttons.save"
*/
type NestedKeyOf<T, P extends string = ""> = {
[K in keyof T & string]: T[K] extends Record<string, unknown>
? NestedKeyOf<T[K], P extends "" ? K : `${P}.${K}`>
: P extends ""
? K
: `${P}.${K}`;
}[keyof T & string];
/** All valid translation keys derived from en/Resources.json */
export type ResourceKey = NestedKeyOf<typeof enResources>;
/**
* Type-safe translation function bound to the "Resources" namespace.
* Use this everywhere—class components, functional components, and non-React code.
*/
export const t = (key: ResourceKey, options?: Record<string, unknown>): string =>
(i18n.t as (key: string, options?: unknown) => string)(key, { ns: "Resources", ...options });

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "Tamam",
"cancel": "İptal",
"close": "Kapat",
"save": "Kaydet",
"delete": "Sil",
"update": "Güncelleştir",
"discard": "At",
"execute": "Execute",
"loading": "Yükleniyor",
"loadingEllipsis": "Yükleniyor...",
"next": "Sonraki",
"previous": "Önceki",
"yes": "Evet",
"no": "Hayır",
"result": "Sonuç",
"learnMore": "Daha fazla bilgi edinin",
"getStarted": "Kullanmaya başlayın",
"retry": "Yeniden dene",
"apply": "Uygula",
"refresh": "Yenile",
"copy": "Kopyala",
"create": "Oluştur",
"confirm": "Onayla",
"open": "Aç",
"rename": "Yeniden adlandır",
"download": "İndir",
"upload": "Karşıya yükle",
"connect": "Bağlan",
"remove": "Kaldır",
"increaseValueBy1": "Değeri 1 artır",
"decreaseValueBy1": "Değeri 1 azalt"
},
"splashScreen": {
"title": {
"default": "Azure Cosmos DB'ye hoş geldiniz",
"postgres": "Azure Cosmos DB for PostgreSQL'e hoş geldiniz",
"vcoreMongo": "Azure DocumentDB'ye (MongoDB uyumluluğu ile) hoş geldiniz"
},
"subtitle": {
"default": "Her ölçeğe uygun, global olarak dağıtılan çok modelli veritabanı hizmeti",
"getStarted": "Örnek veri kümelerimizi, belgelerimizi ve ek araçlarımızı kullanmaya başlayın."
},
"quickStart": {
"title": "Launch quick start",
"description": "Launch a quick start tutorial to get started with sample data"
},
"newCollection": {
"title": "New {{collectionName}}",
"description": "Create a new container for storage and throughput"
},
"samplesGallery": {
"title": "Azure Cosmos DB Samples Gallery",
"description": "Discover samples that showcase scalable, intelligent app patterns. Try one now to see how fast you can go from concept to code with Cosmos DB"
},
"connectCard": {
"title": "Connect",
"description": "Prefer using your own choice of tooling? Find the connection string you need to connect",
"pgAdmin": {
"title": "Connect with pgAdmin",
"description": "Prefer pgAdmin? Find your connection strings here"
},
"vsCode": {
"title": "VS Code ile Bağlan",
"description": "Query and Manage your MongoDB and DocumentDB clusters in Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Create table and interact with data using PostgreSQL's shell interface"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Create a collection and interact with data using MongoDB's shell interface"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "New to Cosmos DB PGSQL?",
"body": "Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you can find sample data, query."
},
"resetPassword": {
"headline": "Create your password",
"body": "If you haven't changed your password yet, change it now."
},
"coachMark": {
"headline": "Start with sample {{collectionName}}",
"body": "You will be guided to create a sample container with sample data, then we will give you a tour of data explorer. You can also cancel launching this tour and explore yourself"
}
},
"sections": {
"recents": "Recents",
"clearRecents": "Clear Recents",
"top3": "Top 3 things you need to know",
"learningResources": "Learning Resources",
"nextSteps": "Next steps",
"tipsAndLearnMore": "Tips & learn more",
"notebook": "Notebook",
"needHelp": "Need help?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Advanced Modeling Patterns",
"description": "Learn advanced strategies to optimize your database."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn to apply data model and partitioning strategies."
},
"resourcePlanning": {
"title": "Plan Your Resource Requirements",
"description": "Get to know the different configuration choices."
}
},
"mongo": {
"whatIsMongo": {
"title": "What is the MongoDB API?",
"description": "Understand Azure Cosmos DB for MongoDB and its features."
},
"features": {
"title": "Features and Syntax",
"description": "Discover the advantages and features"
},
"migrate": {
"title": "Migrate Your Data",
"description": "Pre-migration steps for moving data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Build a Java App",
"description": "Create a Java app using an SDK."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works."
},
"requestUnits": {
"title": "Request Units (RUs)",
"description": "Understand RU charges."
}
},
"gremlin": {
"dataModeling": {
"title": "Data Modeling",
"description": "Graph data modeling recommendations"
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works"
},
"queryData": {
"title": "Query Data",
"description": "Querying data with Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "What is the Table API?",
"description": "Understand Azure Cosmos DB for Table and its features"
},
"migrate": {
"title": "Migrate your data",
"description": "Learn how to migrate your data"
},
"faq": {
"title": "Azure Cosmos DB for Table FAQs",
"description": "Common questions about Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Data Explorer keyboard shortcuts",
"description": "Learn keyboard shortcuts to navigate Data Explorer."
},
"liveTv": {
"title": "Learn the Fundamentals",
"description": "Watch Azure Cosmos DB Live TV show introductory and how to videos."
},
"sql": {
"sdk": {
"title": "Get Started using an SDK",
"description": "Learn about the Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrate Your Data",
"description": "Migrate data using Azure services and open-source solutions."
}
},
"mongo": {
"nodejs": {
"title": "Build an app with Node.js",
"description": "Create a Node.js app."
},
"gettingStarted": {
"title": "Getting Started Guide",
"description": "Learn the basics to get started."
}
},
"cassandra": {
"createContainer": {
"title": "Create a Container",
"description": "Get to know the create a container options."
},
"throughput": {
"title": "Provision Throughput",
"description": "Learn how to configure throughput."
}
},
"gremlin": {
"getStarted": {
"title": "Get Started ",
"description": "Create, query, and traverse using the Gremlin console"
},
"importData": {
"title": "Import Graph Data",
"description": "Learn Bulk ingestion data using BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Build a .NET App",
"description": "How to access Azure Cosmos DB for Table from a .NET app."
},
"java": {
"title": "Build a Java App",
"description": "Create a Azure Cosmos DB for Table app with Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Data Modeling",
"distributionColumn": "How to choose a Distribution Column",
"buildApps": "Build Apps with Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrate Data",
"vectorSearch": "Build AI apps with Vector Search",
"buildApps": "Build Apps with Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Performance Tuning",
"diagnosticQueries": "Useful Diagnostic Queries",
"sqlReference": "Distributed SQL Reference"
},
"vcoreMongo": {
"vectorSearch": "Vector Search",
"textIndexing": "Text Indexing",
"troubleshoot": "Troubleshoot common issues"
}
},
"fabric": {
"buildTitle": "Build your database",
"useTitle": "Use your database",
"newContainer": {
"title": "New container",
"description": "Create a destination container to store your data"
},
"sampleData": {
"title": "Sample Data",
"description": "Load sample data in your database"
},
"sampleVectorData": {
"title": "Sample Vector Data",
"description": "Load sample vector data with text-embedding-ada-002"
},
"appDevelopment": {
"title": "App development",
"description": "Start here to use an SDK to build your apps"
},
"sampleGallery": {
"title": "Sample Gallery",
"description": "Get real-world end-to-end samples"
}
},
"sampleDataDialog": {
"title": "Sample Data",
"startButton": "Start",
"createPrompt": "Create a container \"{{containerName}}\" and import sample data into it. This may take a few minutes.",
"creatingContainer": "Creating container \"{{containerName}}\"...",
"importingData": "Importing data into \"{{containerName}}\"...",
"success": "Successfully created \"{{containerName}}\" with sample data.",
"errorContainerExists": "The container \"{{containerName}}\" in database \"{{databaseName}}\" already exists. Please delete it and retry.",
"errorCreateContainer": "Failed to create container: {{error}}",
"errorImportData": "Failed to import data: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "确定",
"cancel": "取消",
"close": "关闭",
"save": "保存",
"delete": "删除",
"update": "更新",
"discard": "放弃",
"execute": "执行",
"loading": "正在加载",
"loadingEllipsis": "正在加载...",
"next": "下一步",
"previous": "上一步",
"yes": "是",
"no": "否",
"result": "结果",
"learnMore": "了解详细信息",
"getStarted": "开始使用",
"retry": "重试",
"apply": "应用",
"refresh": "刷新",
"copy": "复制",
"create": "创建",
"confirm": "确认",
"open": "打开",
"rename": "重命名",
"download": "下载",
"upload": "上传",
"connect": "连接",
"remove": "删除",
"increaseValueBy1": "将值增加 1",
"decreaseValueBy1": "将值减少 1"
},
"splashScreen": {
"title": {
"default": "欢迎使用 Azure Cosmos DB",
"postgres": "欢迎使用 Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "欢迎使用 Azure DocumentDB (具有 MongoDB 兼容性)"
},
"subtitle": {
"default": "任何规模的全球分布式多模型数据库服务",
"getStarted": "开始使用我们的示例数据集、文档和其他工具。"
},
"quickStart": {
"title": "启动快速入门",
"description": "启动快速入门教程,开始使用示例数据"
},
"newCollection": {
"title": "新建 {{collectionName}}",
"description": "创建用于存储和吞吐量的新容器"
},
"samplesGallery": {
"title": "Azure Cosmos DB 示例库",
"description": "发现展示可扩展智能应用模式的示例。立即试用,体验如何通过 Cosmos DB 快速从概念转变到代码"
},
"connectCard": {
"title": "连接",
"description": "更喜欢使用自己选择的工具?查找需要连接的连接字符串",
"pgAdmin": {
"title": "使用 pgAdmin 连接",
"description": "首选 pgAdmin?在此处查找连接字符串"
},
"vsCode": {
"title": "与 VS Code 连接",
"description": "在 Visual Studio Code 中查询和管理 MongoDB 和 DocumentDB 群集"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "使用 PostgreSQL shell 接口创建表并与数据交互"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "使用 MongoDB shell 接口创建集合并与数据交互"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "不熟悉 Cosmos DB PGSQL?",
"body": "欢迎!如果你不熟悉 Cosmos DB PGSQL需要入门帮助可在此处找到示例数据和查询。"
},
"resetPassword": {
"headline": "创建密码",
"body": "如果尚未更改密码,请立即更改。"
},
"coachMark": {
"headline": "从示例 {{collectionName}} 开始",
"body": "系统将引导你创建包含示例数据的示例容器,然后带你了解数据资源管理器。你也可以取消此教程,改为自行探索"
}
},
"sections": {
"recents": "最近使用",
"clearRecents": "清除最近使用记录",
"top3": "你需要了解的三大要点",
"learningResources": "学习资源",
"nextSteps": "后续步骤",
"tipsAndLearnMore": "提示和详细信息",
"notebook": "笔记本",
"needHelp": "需要帮助?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "高级建模模式",
"description": "了解用于优化数据库的高级策略。"
},
"partitioning": {
"title": "分区最佳做法",
"description": "了解如何应用数据模型和分区策略。"
},
"resourcePlanning": {
"title": "规划资源需求",
"description": "了解不同的配置选择。"
}
},
"mongo": {
"whatIsMongo": {
"title": "什么是 MongoDB API?",
"description": "了解 Azure Cosmos DB for MongoDB 及其功能。"
},
"features": {
"title": "功能和语法",
"description": "了解优势和功能"
},
"migrate": {
"title": "迁移数据",
"description": "用于移动数据的迁移前步骤"
}
},
"cassandra": {
"buildJavaApp": {
"title": "构建 Java 应用",
"description": "使用 SDK 创建 Java 应用。"
},
"partitioning": {
"title": "分区最佳做法",
"description": "了解分区的工作原理。"
},
"requestUnits": {
"title": "请求单位(RU)",
"description": "了解 RU 费用。"
}
},
"gremlin": {
"dataModeling": {
"title": "数据建模",
"description": "图形数据建模建议"
},
"partitioning": {
"title": "分区最佳做法",
"description": "了解分区的工作原理"
},
"queryData": {
"title": "查询数据",
"description": "使用 Gremlin 查询数据"
}
},
"tables": {
"whatIsTable": {
"title": "什么是 Table API?",
"description": "了解 Azure Cosmos DB for Table 及其功能"
},
"migrate": {
"title": "迁移数据",
"description": "了解如何迁移数据"
},
"faq": {
"title": "Azure Cosmos DB for Table 常见问题解答",
"description": "有关 Azure Cosmos DB for Table 的常见问题"
}
}
},
"learningResources": {
"shortcuts": {
"title": "数据资源管理器键盘快捷方式",
"description": "了解浏览数据资源管理器的键盘快捷方式。"
},
"liveTv": {
"title": "了解基础知识",
"description": "观看 Azure Cosmos DB 直播节目介绍及操作方法视频。"
},
"sql": {
"sdk": {
"title": "开始使用 SDK",
"description": "了解 Azure Cosmos DB SDK。"
},
"migrate": {
"title": "迁移数据",
"description": "使用 Azure 服务和开源解决方案迁移数据。"
}
},
"mongo": {
"nodejs": {
"title": "使用 Node.js 构建应用",
"description": "创建 Node.js 应用。"
},
"gettingStarted": {
"title": "入门指南",
"description": "了解入门的基础知识。"
}
},
"cassandra": {
"createContainer": {
"title": "创建容器",
"description": "了解创建容器的选项。"
},
"throughput": {
"title": "预配吞吐量",
"description": "了解如何配置吞吐量。"
}
},
"gremlin": {
"getStarted": {
"title": "开始 ",
"description": "使用 Gremlin 控制台执行创建、查询和遍历"
},
"importData": {
"title": "导入图形数据",
"description": "了解如何使用 BulkExecutor 批量引入数据"
}
},
"tables": {
"dotnet": {
"title": "构建 .NET 应用",
"description": "如何从 .NET 应用访问 Azure Cosmos DB for Table。"
},
"java": {
"title": "构建 Java 应用",
"description": "使用 Java SDK 创建 Azure Cosmos DB for Table 应用 "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "数据建模",
"distributionColumn": "如何选择分布列",
"buildApps": "使用 Python/Java/Django 构建应用"
},
"vcoreMongo": {
"migrateData": "迁移数据",
"vectorSearch": "使用矢量搜索功能构建 AI 应用",
"buildApps": "使用 Nodejs 构建应用"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "性能优化",
"diagnosticQueries": "有用的诊断查询",
"sqlReference": "分布式 SQL 参考"
},
"vcoreMongo": {
"vectorSearch": "矢量搜索",
"textIndexing": "文本索引",
"troubleshoot": "对常见问题进行故障排除"
}
},
"fabric": {
"buildTitle": "生成数据库",
"useTitle": "使用你的数据库",
"newContainer": {
"title": "新容器",
"description": "创建用于存储数据的目标容器"
},
"sampleData": {
"title": "示例数据",
"description": "在数据库中加载示例数据"
},
"sampleVectorData": {
"title": "示例矢量数据",
"description": "使用 text-embedding-ada-002 加载示例矢量数据"
},
"appDevelopment": {
"title": "应用开发",
"description": "从此处开始使用 SDK 来构建应用"
},
"sampleGallery": {
"title": "示例库",
"description": "获取真实的端到端示例"
}
},
"sampleDataDialog": {
"title": "示例数据",
"startButton": "开始",
"createPrompt": "创建容器“{{containerName}}”,并将示例数据导入其中。这可能需要几分钟时间。",
"creatingContainer": "正在创建容器“{{containerName}}”...",
"importingData": "正在将数据导入“{{containerName}}”...",
"success": "已成功使用示例数据创建“{{containerName}}”。",
"errorContainerExists": "数据库“{{databaseName}}”中的容器“{{containerName}}”已存在。请将其删除,然后重试。",
"errorCreateContainer": "未能创建容器: {{error}}",
"errorImportData": "未能导入数据: {{error}}"
}
}
}

View File

@@ -1,295 +0,0 @@
{
"common": {
"ok": "確定",
"cancel": "取消",
"close": "關閉",
"save": "儲存",
"delete": "刪除",
"update": "更新",
"discard": "捨棄",
"execute": "Execute",
"loading": "正在載入",
"loadingEllipsis": "正在載入...",
"next": "下一個",
"previous": "上一步",
"yes": "是",
"no": "否",
"result": "結果",
"learnMore": "深入了解",
"getStarted": "開始使用",
"retry": "重試",
"apply": "套用",
"refresh": "重新整理",
"copy": "複製",
"create": "建立",
"confirm": "確認",
"open": "開啟",
"rename": "重新命名",
"download": "下載",
"upload": "上傳",
"connect": "連線",
"remove": "移除",
"increaseValueBy1": "將值增加 1",
"decreaseValueBy1": "將值減少 1"
},
"splashScreen": {
"title": {
"default": "歡迎使用 Azure Cosmos DB",
"postgres": "歡迎使用 Azure Cosmos DB for PostgreSQL",
"vcoreMongo": "歡迎使用 Azure DocumentDB (具 MongoDB 相容性)"
},
"subtitle": {
"default": "適用於任何規模的全域散發、多模型資料庫服務",
"getStarted": "開始使用我們的樣本資料集、文件和其他工具。"
},
"quickStart": {
"title": "Launch quick start",
"description": "Launch a quick start tutorial to get started with sample data"
},
"newCollection": {
"title": "New {{collectionName}}",
"description": "Create a new container for storage and throughput"
},
"samplesGallery": {
"title": "Azure Cosmos DB Samples Gallery",
"description": "Discover samples that showcase scalable, intelligent app patterns. Try one now to see how fast you can go from concept to code with Cosmos DB"
},
"connectCard": {
"title": "Connect",
"description": "Prefer using your own choice of tooling? Find the connection string you need to connect",
"pgAdmin": {
"title": "Connect with pgAdmin",
"description": "Prefer pgAdmin? Find your connection strings here"
},
"vsCode": {
"title": "與 VS Code 連線",
"description": "Query and Manage your MongoDB and DocumentDB clusters in Visual Studio Code"
}
},
"shell": {
"postgres": {
"title": "PostgreSQL Shell",
"description": "Create table and interact with data using PostgreSQL's shell interface"
},
"vcoreMongo": {
"title": "Mongo Shell",
"description": "Create a collection and interact with data using MongoDB's shell interface"
}
},
"teachingBubble": {
"newToPostgres": {
"headline": "New to Cosmos DB PGSQL?",
"body": "Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you can find sample data, query."
},
"resetPassword": {
"headline": "Create your password",
"body": "If you haven't changed your password yet, change it now."
},
"coachMark": {
"headline": "Start with sample {{collectionName}}",
"body": "You will be guided to create a sample container with sample data, then we will give you a tour of data explorer. You can also cancel launching this tour and explore yourself"
}
},
"sections": {
"recents": "Recents",
"clearRecents": "Clear Recents",
"top3": "Top 3 things you need to know",
"learningResources": "Learning Resources",
"nextSteps": "Next steps",
"tipsAndLearnMore": "Tips & learn more",
"notebook": "Notebook",
"needHelp": "Need help?"
},
"top3Items": {
"sql": {
"advancedModeling": {
"title": "Advanced Modeling Patterns",
"description": "Learn advanced strategies to optimize your database."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn to apply data model and partitioning strategies."
},
"resourcePlanning": {
"title": "Plan Your Resource Requirements",
"description": "Get to know the different configuration choices."
}
},
"mongo": {
"whatIsMongo": {
"title": "What is the MongoDB API?",
"description": "Understand Azure Cosmos DB for MongoDB and its features."
},
"features": {
"title": "Features and Syntax",
"description": "Discover the advantages and features"
},
"migrate": {
"title": "Migrate Your Data",
"description": "Pre-migration steps for moving data"
}
},
"cassandra": {
"buildJavaApp": {
"title": "Build a Java App",
"description": "Create a Java app using an SDK."
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works."
},
"requestUnits": {
"title": "Request Units (RUs)",
"description": "Understand RU charges."
}
},
"gremlin": {
"dataModeling": {
"title": "Data Modeling",
"description": "Graph data modeling recommendations"
},
"partitioning": {
"title": "Partitioning Best Practices",
"description": "Learn how partitioning works"
},
"queryData": {
"title": "Query Data",
"description": "Querying data with Gremlin"
}
},
"tables": {
"whatIsTable": {
"title": "What is the Table API?",
"description": "Understand Azure Cosmos DB for Table and its features"
},
"migrate": {
"title": "Migrate your data",
"description": "Learn how to migrate your data"
},
"faq": {
"title": "Azure Cosmos DB for Table FAQs",
"description": "Common questions about Azure Cosmos DB for Table"
}
}
},
"learningResources": {
"shortcuts": {
"title": "Data Explorer keyboard shortcuts",
"description": "Learn keyboard shortcuts to navigate Data Explorer."
},
"liveTv": {
"title": "Learn the Fundamentals",
"description": "Watch Azure Cosmos DB Live TV show introductory and how to videos."
},
"sql": {
"sdk": {
"title": "Get Started using an SDK",
"description": "Learn about the Azure Cosmos DB SDK."
},
"migrate": {
"title": "Migrate Your Data",
"description": "Migrate data using Azure services and open-source solutions."
}
},
"mongo": {
"nodejs": {
"title": "Build an app with Node.js",
"description": "Create a Node.js app."
},
"gettingStarted": {
"title": "Getting Started Guide",
"description": "Learn the basics to get started."
}
},
"cassandra": {
"createContainer": {
"title": "Create a Container",
"description": "Get to know the create a container options."
},
"throughput": {
"title": "Provision Throughput",
"description": "Learn how to configure throughput."
}
},
"gremlin": {
"getStarted": {
"title": "Get Started ",
"description": "Create, query, and traverse using the Gremlin console"
},
"importData": {
"title": "Import Graph Data",
"description": "Learn Bulk ingestion data using BulkExecutor"
}
},
"tables": {
"dotnet": {
"title": "Build a .NET App",
"description": "How to access Azure Cosmos DB for Table from a .NET app."
},
"java": {
"title": "Build a Java App",
"description": "Create a Azure Cosmos DB for Table app with Java SDK "
}
}
},
"nextStepItems": {
"postgres": {
"dataModeling": "Data Modeling",
"distributionColumn": "How to choose a Distribution Column",
"buildApps": "Build Apps with Python/Java/Django"
},
"vcoreMongo": {
"migrateData": "Migrate Data",
"vectorSearch": "Build AI apps with Vector Search",
"buildApps": "Build Apps with Nodejs"
}
},
"learnMoreItems": {
"postgres": {
"performanceTuning": "Performance Tuning",
"diagnosticQueries": "Useful Diagnostic Queries",
"sqlReference": "Distributed SQL Reference"
},
"vcoreMongo": {
"vectorSearch": "Vector Search",
"textIndexing": "Text Indexing",
"troubleshoot": "Troubleshoot common issues"
}
},
"fabric": {
"buildTitle": "Build your database",
"useTitle": "Use your database",
"newContainer": {
"title": "New container",
"description": "Create a destination container to store your data"
},
"sampleData": {
"title": "Sample Data",
"description": "Load sample data in your database"
},
"sampleVectorData": {
"title": "Sample Vector Data",
"description": "Load sample vector data with text-embedding-ada-002"
},
"appDevelopment": {
"title": "App development",
"description": "Start here to use an SDK to build your apps"
},
"sampleGallery": {
"title": "Sample Gallery",
"description": "Get real-world end-to-end samples"
}
},
"sampleDataDialog": {
"title": "Sample Data",
"startButton": "Start",
"createPrompt": "Create a container \"{{containerName}}\" and import sample data into it. This may take a few minutes.",
"creatingContainer": "Creating container \"{{containerName}}\"...",
"importingData": "Importing data into \"{{containerName}}\"...",
"success": "Successfully created \"{{containerName}}\" with sample data.",
"errorContainerExists": "The container \"{{containerName}}\" in database \"{{databaseName}}\" already exists. Please delete it and retry.",
"errorCreateContainer": "Failed to create container: {{error}}",
"errorImportData": "Failed to import data: {{error}}"
}
}
}

View File

@@ -105,12 +105,9 @@ const App = (): JSX.Element => {
// Scenario-based health tracking: start ApplicationLoad and complete phases.
const { startScenario, completePhase } = useMetricScenario();
React.useEffect(() => {
// Only start scenario after config is initialized to avoid race conditions
// with message handlers that depend on configContext.platform
if (config) {
startScenario(MetricScenario.ApplicationLoad);
}
}, [config, startScenario]);
startScenario(MetricScenario.ApplicationLoad);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
React.useEffect(() => {
if (explorer) {
@@ -119,9 +116,6 @@ const App = (): JSX.Element => {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [explorer]);
// Track interactive phase for both ContainerCopyPanel and DivExplorer paths
useInteractive(MetricScenario.ApplicationLoad, !!config);
if (!explorer) {
return <LoadingExplorer />;
}
@@ -148,6 +142,7 @@ const App = (): JSX.Element => {
const DivExplorer: React.FC<{ explorer: Explorer }> = ({ explorer }) => {
const isCarouselOpen = useCarousel((state) => state.shouldOpen);
const isCopilotCarouselOpen = useCarousel((state) => state.showCopilotCarousel);
useInteractive(MetricScenario.ApplicationLoad);
return (
<div

View File

@@ -1,182 +0,0 @@
import { ARMError } from "../Utils/arm/request";
import { isExpectedError } from "./ErrorClassification";
describe("ErrorClassification", () => {
describe("isExpectedError", () => {
describe("ARMError with expected codes", () => {
it("returns true for AuthorizationFailed code", () => {
const error = new ARMError("Authorization failed");
error.code = "AuthorizationFailed";
expect(isExpectedError(error)).toBe(true);
});
it("returns true for Forbidden code", () => {
const error = new ARMError("Forbidden");
error.code = "Forbidden";
expect(isExpectedError(error)).toBe(true);
});
it("returns true for Unauthorized code", () => {
const error = new ARMError("Unauthorized");
error.code = "Unauthorized";
expect(isExpectedError(error)).toBe(true);
});
it("returns true for InvalidAuthenticationToken code", () => {
const error = new ARMError("Invalid token");
error.code = "InvalidAuthenticationToken";
expect(isExpectedError(error)).toBe(true);
});
it("returns true for ExpiredAuthenticationToken code", () => {
const error = new ARMError("Token expired");
error.code = "ExpiredAuthenticationToken";
expect(isExpectedError(error)).toBe(true);
});
it("returns true for numeric 401 code", () => {
const error = new ARMError("Unauthorized");
error.code = 401;
expect(isExpectedError(error)).toBe(true);
});
it("returns true for numeric 403 code", () => {
const error = new ARMError("Forbidden");
error.code = 403;
expect(isExpectedError(error)).toBe(true);
});
it("returns false for unexpected ARM error code", () => {
const error = new ARMError("Internal error");
error.code = "InternalServerError";
expect(isExpectedError(error)).toBe(false);
});
it("returns false for numeric 500 code", () => {
const error = new ARMError("Server error");
error.code = 500;
expect(isExpectedError(error)).toBe(false);
});
});
describe("MSAL AuthError with expected errorCodes", () => {
it("returns true for popup_window_error", () => {
const error = { errorCode: "popup_window_error", message: "Popup blocked" };
expect(isExpectedError(error)).toBe(true);
});
it("returns true for interaction_required", () => {
const error = { errorCode: "interaction_required", message: "User interaction required" };
expect(isExpectedError(error)).toBe(true);
});
it("returns true for user_cancelled", () => {
const error = { errorCode: "user_cancelled", message: "User cancelled" };
expect(isExpectedError(error)).toBe(true);
});
it("returns true for consent_required", () => {
const error = { errorCode: "consent_required", message: "Consent required" };
expect(isExpectedError(error)).toBe(true);
});
it("returns true for login_required", () => {
const error = { errorCode: "login_required", message: "Login required" };
expect(isExpectedError(error)).toBe(true);
});
it("returns true for no_account_error", () => {
const error = { errorCode: "no_account_error", message: "No account" };
expect(isExpectedError(error)).toBe(true);
});
it("returns false for unexpected MSAL error code", () => {
const error = { errorCode: "unknown_error", message: "Unknown" };
expect(isExpectedError(error)).toBe(false);
});
});
describe("HTTP status codes", () => {
it("returns true for error with status 401", () => {
const error = { status: 401, message: "Unauthorized" };
expect(isExpectedError(error)).toBe(true);
});
it("returns true for error with status 403", () => {
const error = { status: 403, message: "Forbidden" };
expect(isExpectedError(error)).toBe(true);
});
it("returns false for error with status 500", () => {
const error = { status: 500, message: "Internal Server Error" };
expect(isExpectedError(error)).toBe(false);
});
it("returns false for error with status 404", () => {
const error = { status: 404, message: "Not Found" };
expect(isExpectedError(error)).toBe(false);
});
});
describe("Firewall error message pattern", () => {
it("returns true for firewall error in Error message", () => {
const error = new Error("Request blocked by firewall");
expect(isExpectedError(error)).toBe(true);
});
it("returns true for IP not allowed error", () => {
const error = new Error("Client IP address is not allowed");
expect(isExpectedError(error)).toBe(true);
});
it("returns true for ip not allowed (no 'address')", () => {
const error = new Error("Your ip not allowed to access this resource");
expect(isExpectedError(error)).toBe(true);
});
it("returns true for string error with firewall", () => {
expect(isExpectedError("firewall rules prevent access")).toBe(true);
});
it("returns true for case-insensitive firewall match", () => {
const error = new Error("FIREWALL blocked request");
expect(isExpectedError(error)).toBe(true);
});
it("returns false for unrelated error message", () => {
const error = new Error("Database connection failed");
expect(isExpectedError(error)).toBe(false);
});
});
describe("Edge cases", () => {
it("returns false for null", () => {
expect(isExpectedError(null)).toBe(false);
});
it("returns false for undefined", () => {
expect(isExpectedError(undefined)).toBe(false);
});
it("returns false for empty object", () => {
expect(isExpectedError({})).toBe(false);
});
it("returns false for plain Error without expected patterns", () => {
const error = new Error("Something went wrong");
expect(isExpectedError(error)).toBe(false);
});
it("returns false for string without firewall pattern", () => {
expect(isExpectedError("Generic error occurred")).toBe(false);
});
it("handles error with multiple matching criteria", () => {
// ARMError with both code and firewall message
const error = new ARMError("Request blocked by firewall");
error.code = "Forbidden";
expect(isExpectedError(error)).toBe(true);
});
});
});
});

View File

@@ -1,109 +0,0 @@
import { ARMError } from "../Utils/arm/request";
/**
* Expected error codes that should not mark scenarios as unhealthy.
* These represent expected failures like auth issues, permission errors, and user actions.
*/
// ARM error codes (string)
const EXPECTED_ARM_ERROR_CODES: Set<string> = new Set([
"AuthorizationFailed",
"Forbidden",
"Unauthorized",
"AuthenticationFailed",
"InvalidAuthenticationToken",
"ExpiredAuthenticationToken",
"AuthorizationPermissionMismatch",
]);
// HTTP status codes that indicate expected failures
const EXPECTED_HTTP_STATUS_CODES: Set<number> = new Set([
401, // Unauthorized
403, // Forbidden
]);
// MSAL error codes (string)
const EXPECTED_MSAL_ERROR_CODES: Set<string> = new Set([
"popup_window_error",
"interaction_required",
"user_cancelled",
"consent_required",
"login_required",
"no_account_error",
"monitor_window_timeout",
"empty_window_error",
]);
// Firewall error message pattern (only case where we check message content)
const FIREWALL_ERROR_PATTERN = /firewall|ip\s*(address)?\s*(is\s*)?not\s*allowed/i;
/**
* Interface for MSAL AuthError-like objects
*/
interface MsalAuthError {
errorCode?: string;
}
/**
* Interface for errors with HTTP status
*/
interface HttpError {
status?: number;
}
/**
* Determines if an error is an expected failure that should not mark the scenario as unhealthy.
*
* Expected failures include:
* - Authentication/authorization errors (user not logged in, permissions)
* - Firewall blocking errors
* - User-cancelled operations
*
* @param error - The error to classify
* @returns true if the error is expected and should not affect health metrics
*/
export function isExpectedError(error: unknown): boolean {
if (!error) {
return false;
}
// Check ARMError code
if (error instanceof ARMError && error.code !== undefined) {
if (typeof error.code === "string" && EXPECTED_ARM_ERROR_CODES.has(error.code)) {
return true;
}
if (typeof error.code === "number" && EXPECTED_HTTP_STATUS_CODES.has(error.code)) {
return true;
}
}
// Check for MSAL AuthError (has errorCode property)
const msalError = error as MsalAuthError;
if (msalError.errorCode && typeof msalError.errorCode === "string") {
if (EXPECTED_MSAL_ERROR_CODES.has(msalError.errorCode)) {
return true;
}
}
// Check HTTP status on generic errors
const httpError = error as HttpError;
if (httpError.status && typeof httpError.status === "number") {
if (EXPECTED_HTTP_STATUS_CODES.has(httpError.status)) {
return true;
}
}
// Check for firewall error in message (the only message-based check)
if (error instanceof Error && error.message) {
if (FIREWALL_ERROR_PATTERN.test(error.message)) {
return true;
}
}
// Check for string errors with firewall pattern
if (typeof error === "string" && FIREWALL_ERROR_PATTERN.test(error)) {
return true;
}
return false;
}

View File

@@ -15,11 +15,6 @@ export const reportUnhealthy = (scenario: MetricScenario, platform: Platform, ap
send({ platform, api, scenario, healthy: false });
const send = async (event: MetricEvent): Promise<Response> => {
// Skip metrics emission during local development
if (process.env.NODE_ENV === "development") {
return Promise.resolve(new Response(null, { status: 200 }));
}
const url = createUri(configContext?.PORTAL_BACKEND_ENDPOINT, RELATIVE_PATH);
const authHeader = getAuthorizationHeader();

View File

@@ -1,231 +0,0 @@
/**
* @jest-environment jsdom
*/
import { configContext } from "../ConfigContext";
import { updateUserContext } from "../UserContext";
import MetricScenario, { reportHealthy, reportUnhealthy } from "./MetricEvents";
import { ApplicationMetricPhase, CommonMetricPhase } from "./ScenarioConfig";
import { scenarioMonitor } from "./ScenarioMonitor";
// Mock the MetricEvents module
jest.mock("./MetricEvents", () => ({
__esModule: true,
default: {
ApplicationLoad: "ApplicationLoad",
DatabaseLoad: "DatabaseLoad",
},
reportHealthy: jest.fn().mockResolvedValue({ ok: true }),
reportUnhealthy: jest.fn().mockResolvedValue({ ok: true }),
}));
// Mock configContext
jest.mock("../ConfigContext", () => ({
configContext: {
platform: "Portal",
PORTAL_BACKEND_ENDPOINT: "https://test.portal.azure.com",
},
Platform: {
Portal: "Portal",
Hosted: "Hosted",
Emulator: "Emulator",
Fabric: "Fabric",
},
}));
describe("ScenarioMonitor", () => {
beforeEach(() => {
jest.clearAllMocks();
// Use legacy fake timers to avoid conflicts with performance API
jest.useFakeTimers({ legacyFakeTimers: true });
// Ensure performance mock is available (setupTests.ts sets this but fake timers may override)
if (typeof performance.mark !== "function") {
Object.defineProperty(global, "performance", {
writable: true,
configurable: true,
value: {
mark: jest.fn(),
measure: jest.fn(),
clearMarks: jest.fn(),
clearMeasures: jest.fn(),
getEntriesByName: jest.fn().mockReturnValue([{ startTime: 0 }]),
getEntriesByType: jest.fn().mockReturnValue([]),
now: jest.fn(() => Date.now()),
timeOrigin: Date.now(),
},
});
}
// Reset userContext
updateUserContext({
apiType: "SQL",
});
// Reset the scenario monitor to clear any previous state
scenarioMonitor.reset();
});
afterEach(() => {
// Reset scenarios before switching to real timers
scenarioMonitor.reset();
jest.useRealTimers();
});
describe("markExpectedFailure", () => {
it("sets hasExpectedFailure flag on active scenarios", () => {
// Start a scenario
scenarioMonitor.start(MetricScenario.ApplicationLoad);
// Mark expected failure
scenarioMonitor.markExpectedFailure();
// Let timeout fire - should emit healthy because of expected failure
jest.advanceTimersByTime(10000);
expect(reportHealthy).toHaveBeenCalledWith(MetricScenario.ApplicationLoad, configContext.platform, "SQL");
expect(reportUnhealthy).not.toHaveBeenCalled();
});
it("sets flag on multiple active scenarios", () => {
// Start two scenarios
scenarioMonitor.start(MetricScenario.ApplicationLoad);
scenarioMonitor.start(MetricScenario.DatabaseLoad);
// Mark expected failure - should affect both
scenarioMonitor.markExpectedFailure();
// Let timeouts fire
jest.advanceTimersByTime(10000);
expect(reportHealthy).toHaveBeenCalledTimes(2);
expect(reportUnhealthy).not.toHaveBeenCalled();
});
it("does not affect already emitted scenarios", () => {
// Start scenario
scenarioMonitor.start(MetricScenario.ApplicationLoad);
// Complete all phases to emit
scenarioMonitor.completePhase(MetricScenario.ApplicationLoad, ApplicationMetricPhase.ExplorerInitialized);
scenarioMonitor.completePhase(MetricScenario.ApplicationLoad, CommonMetricPhase.Interactive);
// Now mark expected failure - should not change anything
scenarioMonitor.markExpectedFailure();
// Healthy was called when phases completed
expect(reportHealthy).toHaveBeenCalledTimes(1);
});
});
describe("timeout behavior", () => {
it("emits unhealthy on timeout without expected failure", () => {
scenarioMonitor.start(MetricScenario.ApplicationLoad);
// Let timeout fire without marking expected failure
jest.advanceTimersByTime(10000);
expect(reportUnhealthy).toHaveBeenCalledWith(MetricScenario.ApplicationLoad, configContext.platform, "SQL");
expect(reportHealthy).not.toHaveBeenCalled();
});
it("emits healthy on timeout with expected failure", () => {
scenarioMonitor.start(MetricScenario.ApplicationLoad);
// Mark expected failure
scenarioMonitor.markExpectedFailure();
// Let timeout fire
jest.advanceTimersByTime(10000);
expect(reportHealthy).toHaveBeenCalledWith(MetricScenario.ApplicationLoad, configContext.platform, "SQL");
expect(reportUnhealthy).not.toHaveBeenCalled();
});
it("emits healthy even with partial phase completion and expected failure", () => {
scenarioMonitor.start(MetricScenario.ApplicationLoad);
// Complete one phase
scenarioMonitor.completePhase(MetricScenario.ApplicationLoad, ApplicationMetricPhase.ExplorerInitialized);
// Mark expected failure
scenarioMonitor.markExpectedFailure();
// Let timeout fire (Interactive phase not completed)
jest.advanceTimersByTime(10000);
expect(reportHealthy).toHaveBeenCalled();
expect(reportUnhealthy).not.toHaveBeenCalled();
});
});
describe("failPhase behavior", () => {
it("emits unhealthy immediately on unexpected failure", () => {
scenarioMonitor.start(MetricScenario.DatabaseLoad);
// Fail a phase (simulating unexpected error)
scenarioMonitor.failPhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabasesFetched);
// Should emit unhealthy immediately, not wait for timeout
expect(reportUnhealthy).toHaveBeenCalledWith(MetricScenario.DatabaseLoad, configContext.platform, "SQL");
});
it("does not emit twice after failPhase and timeout", () => {
scenarioMonitor.start(MetricScenario.DatabaseLoad);
// Fail a phase
scenarioMonitor.failPhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabasesFetched);
// Let timeout fire
jest.advanceTimersByTime(10000);
// Should only have emitted once (from failPhase)
expect(reportUnhealthy).toHaveBeenCalledTimes(1);
});
});
describe("completePhase behavior", () => {
it("emits healthy when all phases complete", () => {
scenarioMonitor.start(MetricScenario.ApplicationLoad);
// Complete all required phases
scenarioMonitor.completePhase(MetricScenario.ApplicationLoad, ApplicationMetricPhase.ExplorerInitialized);
scenarioMonitor.completePhase(MetricScenario.ApplicationLoad, CommonMetricPhase.Interactive);
expect(reportHealthy).toHaveBeenCalledWith(MetricScenario.ApplicationLoad, configContext.platform, "SQL");
});
it("does not emit until all phases complete", () => {
scenarioMonitor.start(MetricScenario.ApplicationLoad);
// Complete only one phase
scenarioMonitor.completePhase(MetricScenario.ApplicationLoad, ApplicationMetricPhase.ExplorerInitialized);
expect(reportHealthy).not.toHaveBeenCalled();
expect(reportUnhealthy).not.toHaveBeenCalled();
});
});
describe("scenario isolation", () => {
it("expected failure on one scenario does not affect others after completion", () => {
// Start both scenarios
scenarioMonitor.start(MetricScenario.ApplicationLoad);
scenarioMonitor.start(MetricScenario.DatabaseLoad);
// Complete ApplicationLoad
scenarioMonitor.completePhase(MetricScenario.ApplicationLoad, ApplicationMetricPhase.ExplorerInitialized);
scenarioMonitor.completePhase(MetricScenario.ApplicationLoad, CommonMetricPhase.Interactive);
// Now mark expected failure - should only affect DatabaseLoad
scenarioMonitor.markExpectedFailure();
// Let DatabaseLoad timeout
jest.advanceTimersByTime(10000);
// ApplicationLoad emitted healthy on completion
// DatabaseLoad emits healthy on timeout (expected failure)
expect(reportHealthy).toHaveBeenCalledTimes(2);
expect(reportUnhealthy).not.toHaveBeenCalled();
});
});
});

View File

@@ -21,7 +21,6 @@ interface InternalScenarioContext {
phases: Map<MetricPhase, PhaseContext>; // Track start/end for each phase
timeoutId?: number;
emitted: boolean;
hasExpectedFailure: boolean; // Flag for expected failures (auth, firewall, etc.)
}
class ScenarioMonitor {
@@ -56,13 +55,6 @@ class ScenarioMonitor {
});
}
private devLog(msg: string) {
if (process.env.NODE_ENV === "development") {
// eslint-disable-next-line no-console
console.log(`[Metrics] ${msg}`);
}
}
start(scenario: MetricScenario) {
if (this.contexts.has(scenario)) {
return;
@@ -83,7 +75,6 @@ class ScenarioMonitor {
failed: new Set<MetricPhase>(),
phases: new Map<MetricPhase, PhaseContext>(),
emitted: false,
hasExpectedFailure: false,
};
// Start all required phases at scenario start time
@@ -93,10 +84,6 @@ class ScenarioMonitor {
ctx.phases.set(phase, { startMarkName: phaseStartMarkName });
});
this.devLog(
`scenario_start: ${scenario} | phases=${config.requiredPhases.join(", ")} | timeout=${config.timeoutMs}ms`,
);
traceMark(Action.MetricsScenario, {
event: "scenario_start",
scenario,
@@ -104,28 +91,7 @@ class ScenarioMonitor {
timeoutMs: config.timeoutMs,
});
ctx.timeoutId = window.setTimeout(() => {
const missingPhases = ctx.config.requiredPhases.filter((p) => !ctx.completed.has(p));
this.devLog(
`timeout: ${scenario} | missing=[${missingPhases.join(", ")}] | completed=[${Array.from(ctx.completed).join(
", ",
)}] | documentHidden=${document.hidden} | hasExpectedFailure=${ctx.hasExpectedFailure}`,
);
traceMark(Action.MetricsScenario, {
event: "scenario_timeout",
scenario,
missingPhases: missingPhases.join(","),
completedPhases: Array.from(ctx.completed).join(","),
documentHidden: document.hidden,
hasExpectedFailure: ctx.hasExpectedFailure,
});
// If an expected failure occurred (auth, firewall, etc.), emit healthy instead of unhealthy
const healthy = ctx.hasExpectedFailure;
this.emit(ctx, healthy, true);
}, config.timeoutMs);
ctx.timeoutId = window.setTimeout(() => this.emit(ctx, false, true), config.timeoutMs);
this.contexts.set(scenario, ctx);
}
@@ -164,12 +130,6 @@ class ScenarioMonitor {
const endTimeISO = endEntry ? new Date(navigationStart + endEntry.startTime).toISOString() : undefined;
const durationMs = startEntry && endEntry ? endEntry.startTime - startEntry.startTime : undefined;
this.devLog(
`phase_complete: ${scenario}.${phase} | ${
durationMs !== null && durationMs !== undefined ? `${Math.round(durationMs)}ms` : "?"
} | ${ctx.completed.size}/${ctx.config.requiredPhases.length} phases`,
);
traceSuccess(Action.MetricsScenario, {
event: "phase_complete",
scenario,
@@ -189,13 +149,6 @@ class ScenarioMonitor {
return;
}
// If an expected failure was flagged (auth, firewall, etc.), treat as success.
if (ctx.hasExpectedFailure) {
this.devLog(`phase_fail: ${scenario}.${phase} — expected failure, completing as healthy`);
this.completePhase(scenario, phase);
return;
}
// Mark the explicitly failed phase
performance.mark(`scenario_${scenario}_${phase}_failed`);
ctx.failed.add(phase);
@@ -210,12 +163,6 @@ class ScenarioMonitor {
// Build a snapshot with failure info
const failureSnapshot = this.buildSnapshot(ctx, { final: false, timedOut: false });
this.devLog(
`phase_fail: ${scenario}.${phase} | failed=[${Array.from(ctx.failed).join(", ")}] | completed=[${Array.from(
ctx.completed,
).join(", ")}]`,
);
traceFailure(Action.MetricsScenario, {
event: "phase_fail",
scenario,
@@ -224,28 +171,10 @@ class ScenarioMonitor {
completedPhases: Array.from(ctx.completed).join(","),
});
// Emit unhealthy immediately for unexpected failures
// Emit unhealthy immediately
this.emit(ctx, false, false, failureSnapshot);
}
/**
* Marks that an expected failure occurred (auth, firewall, permissions, etc.).
* When the scenario times out with this flag set, it will emit healthy instead of unhealthy.
* This is called automatically from handleError when an expected error is detected.
*/
markExpectedFailure() {
// Set the flag on all active (non-emitted) scenarios
this.contexts.forEach((ctx) => {
if (!ctx.emitted) {
ctx.hasExpectedFailure = true;
traceMark(Action.MetricsScenario, {
event: "expected_failure_marked",
scenario: ctx.scenario,
});
}
});
}
private tryEmitIfReady(ctx: InternalScenarioContext) {
const allDone = ctx.config.requiredPhases.every((p) => ctx.completed.has(p));
if (!allDone) {
@@ -305,7 +234,6 @@ class ScenarioMonitor {
scenario: ctx.scenario,
healthy,
timedOut,
documentHidden: document.hidden,
platform,
api,
durationMs: finalSnapshot.durationMs,
@@ -318,22 +246,8 @@ class ScenarioMonitor {
ttfb: finalSnapshot.vitals?.ttfb,
});
this.devLog(
`scenario_end: ${ctx.scenario} | ${healthy ? "healthy" : "unhealthy"} | ${
timedOut ? "timed out" : `${Math.round(finalSnapshot.durationMs)}ms`
} | ${JSON.stringify({
completedPhases: finalSnapshot.completed.join(", "),
failedPhases: finalSnapshot.failedPhases?.join(", ") || "none",
platform,
api,
phaseTimings: finalSnapshot.phaseTimings,
vitals: finalSnapshot.vitals,
})}`,
);
// Call portal backend health metrics endpoint
// If healthy is true (either completed successfully or timeout with expected failure), report healthy
if (healthy) {
if (healthy && !timedOut) {
reportHealthy(ctx.scenario, platform, api);
} else {
reportUnhealthy(ctx.scenario, platform, api);
@@ -388,19 +302,6 @@ class ScenarioMonitor {
phaseTimings,
};
}
/**
* Reset all scenarios (for testing purposes only).
* Clears all active contexts and their timeouts.
*/
reset() {
this.contexts.forEach((ctx) => {
if (ctx.timeoutId) {
clearTimeout(ctx.timeoutId);
}
});
this.contexts.clear();
}
}
export const scenarioMonitor = new ScenarioMonitor();

View File

@@ -1,26 +1,20 @@
import React from "react";
import MetricScenario from "./MetricEvents";
import { scenarioMonitor } from "./ScenarioMonitor";
import { useMetricScenario } from "./MetricScenarioProvider";
import { ApplicationMetricPhase, CommonMetricPhase } from "./ScenarioConfig";
/**
* Hook to automatically complete the Interactive phase when the component becomes interactive.
* Uses requestAnimationFrame to complete after the browser has painted.
*
* Calls scenarioMonitor directly (not via React context) so that the effect dependencies
* are only [scenario, enabled] — both stable primitives. This prevents re-renders from
* cancelling the pending rAF due to an unstable context function reference.
*/
export function useInteractive(scenario: MetricScenario, enabled = true) {
export function useInteractive(scenario: MetricScenario) {
const { completePhase } = useMetricScenario();
React.useEffect(() => {
if (!enabled) {
return undefined;
}
const id = requestAnimationFrame(() => {
scenarioMonitor.completePhase(scenario, CommonMetricPhase.Interactive);
requestAnimationFrame(() => {
completePhase(scenario, CommonMetricPhase.Interactive);
});
return () => cancelAnimationFrame(id);
}, [scenario, enabled]);
}, [scenario, completePhase]);
}
/**
@@ -28,20 +22,18 @@ export function useInteractive(scenario: MetricScenario, enabled = true) {
* Tracks tree rendering and completes Interactive phase.
* Only completes DatabaseTreeRendered if the database fetch was successful.
* Note: Scenario must be started before databases are fetched (in refreshExplorer).
*
* Calls scenarioMonitor directly (not via React context) for the same stability reason
* as useInteractive — avoids effect re-runs from unstable context function references.
*/
export function useDatabaseLoadScenario(databaseTreeNodes: unknown[], fetchSucceeded: boolean) {
const { completePhase } = useMetricScenario();
const hasCompletedTreeRenderRef = React.useRef(false);
// Track DatabaseTreeRendered phase (only if fetch succeeded)
React.useEffect(() => {
if (!hasCompletedTreeRenderRef.current && fetchSucceeded) {
hasCompletedTreeRenderRef.current = true;
scenarioMonitor.completePhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabaseTreeRendered);
completePhase(MetricScenario.DatabaseLoad, ApplicationMetricPhase.DatabaseTreeRendered);
}
}, [databaseTreeNodes, fetchSucceeded]);
}, [databaseTreeNodes, fetchSucceeded, completePhase]);
// Track Interactive phase
useInteractive(MetricScenario.DatabaseLoad);

View File

@@ -0,0 +1,88 @@
import { initializeIcons } from "@fluentui/react";
import "bootstrap/dist/css/bootstrap.css";
import React from "react";
import * as ReactDOM from "react-dom";
import { configContext, initializeConfiguration } from "../ConfigContext";
import { GalleryHeaderComponent } from "../Explorer/Controls/Header/GalleryHeaderComponent";
import { GalleryTab } from "../Explorer/Controls/NotebookGallery/GalleryViewerComponent";
import {
NotebookViewerComponent,
NotebookViewerComponentProps,
} from "../Explorer/Controls/NotebookViewer/NotebookViewerComponent";
import * as FileSystemUtil from "../Explorer/Notebook/FileSystemUtil";
import { IGalleryItem, JunoClient } from "../Juno/JunoClient";
import * as GalleryUtils from "../Utils/GalleryUtils";
const onInit = async () => {
initializeIcons();
await initializeConfiguration();
const galleryViewerProps = GalleryUtils.getGalleryViewerProps(window.location.search);
const notebookViewerProps = GalleryUtils.getNotebookViewerProps(window.location.search);
let backNavigationText: string;
let onBackClick: () => void;
if (galleryViewerProps.selectedTab !== undefined) {
backNavigationText = GalleryUtils.getTabTitle(galleryViewerProps.selectedTab);
onBackClick = () =>
(window.location.href = `${configContext.hostedExplorerURL}gallery.html?tab=${
GalleryTab[galleryViewerProps.selectedTab]
}`);
}
const hideInputs = notebookViewerProps.hideInputs;
const notebookUrl = decodeURIComponent(notebookViewerProps.notebookUrl);
const galleryItemId = notebookViewerProps.galleryItemId;
let galleryItem: IGalleryItem;
if (galleryItemId) {
const junoClient = new JunoClient();
const galleryItemJunoResponse = await junoClient.getNotebookInfo(galleryItemId);
galleryItem = galleryItemJunoResponse.data;
}
// The main purpose of hiding the prompt is to hide everything when hiding inputs.
// It is generally not very useful to just hide the prompt.
const hidePrompts = hideInputs;
render(notebookUrl, backNavigationText, hideInputs, hidePrompts, galleryItem, onBackClick);
};
const render = (
notebookUrl: string,
backNavigationText: string,
hideInputs?: boolean,
hidePrompts?: boolean,
galleryItem?: IGalleryItem,
onBackClick?: () => void,
) => {
const props: NotebookViewerComponentProps = {
junoClient: galleryItem ? new JunoClient() : undefined,
notebookUrl,
galleryItem,
backNavigationText,
hideInputs,
hidePrompts,
onBackClick: onBackClick,
onTagClick: undefined,
};
if (galleryItem) {
document.title = FileSystemUtil.stripExtension(galleryItem.name, "ipynb");
}
const element = (
<>
<header>
<GalleryHeaderComponent />
</header>
<div style={{ marginLeft: 120, marginRight: 120 }}>
<NotebookViewerComponent {...props} />
</div>
</>
);
ReactDOM.render(element, document.getElementById("notebookContent"));
};
// Entry point
window.addEventListener("load", onInit);

View File

@@ -37,7 +37,7 @@ const requestFabricToken = async (): Promise<void> => {
scheduleRefreshFabricToken();
} catch (error) {
logConsoleError(error instanceof Error ? error.message : String(error));
logConsoleError(error as string);
throw error;
} finally {
lastRequestTimestamp = undefined;
@@ -105,12 +105,6 @@ const requestAndStoreAccessToken = async (): Promise<void> => {
});
};
export const openRestoreContainerDialog = (): void => {
if (isFabricNative()) {
sendCachedDataMessage(FabricMessageTypes.RestoreContainer, []);
}
};
/**
* Check token validity and schedule a refresh if necessary
* @param tokenTimestamp

View File

@@ -40,7 +40,6 @@ export type Features = {
readonly disableConnectionStringLogin: boolean;
readonly enableContainerCopy: boolean;
readonly enableCloudShell: boolean;
readonly enableRestoreContainer: boolean; // only for Fabric
// can be set via both flight and feature flag
autoscaleDefault: boolean;
@@ -94,7 +93,7 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
notebookBasePath: get("notebookbasepath"),
notebookServerToken: get("notebookservertoken"),
notebookServerUrl: get("notebookserverurl"),
sandboxNotebookOutputs: true,
sandboxNotebookOutputs: "true" === get("sandboxnotebookoutputs", "true"),
selfServeType: get("selfservetype"),
showMinRUSurvey: "true" === get("showminrusurvey"),
ttl90Days: "true" === get("ttl90days"),
@@ -112,7 +111,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
enablePriorityBasedExecution: "true" === get("enableprioritybasedexecution"),
disableConnectionStringLogin: "true" === get("disableconnectionstringlogin"),
enableContainerCopy: "true" === get("enablecontainercopy"),
enableRestoreContainer: "true" === get("enablerestorecontainer"),
enableCloudShell: true,
};
}

View File

@@ -9,6 +9,7 @@ import {
Stack,
Text,
} from "@fluentui/react";
import { TFunction } from "i18next";
import promiseRetry, { AbortError, Options } from "p-retry";
import React from "react";
import { WithTranslation } from "react-i18next";
@@ -80,7 +81,7 @@ export class SelfServeComponent extends React.Component<SelfServeComponentProps,
private smartUiGeneratorClassName: string;
private retryIntervalInMs: number;
private retryOptions: Options;
private translationFunction: (key: string) => string;
private translationFunction: TFunction;
componentDidMount(): void {
this.performRefresh().then(() => {
@@ -118,7 +119,7 @@ export class SelfServeComponent extends React.Component<SelfServeComponentProps,
this.retryOptions = { forever: true, maxTimeout: this.retryIntervalInMs, minTimeout: this.retryIntervalInMs };
// translation function passed to SelfServeComponent
this.translationFunction = this.props.t as (key: string) => string;
this.translationFunction = this.props.t;
}
private onError = (hasErrors: boolean): void => {

View File

@@ -27,7 +27,7 @@ describe("AuthorizationUtils", () => {
enableKoResourceTree: false,
enableThroughputBuckets: false,
hostedDataExplorer: false,
sandboxNotebookOutputs: true,
sandboxNotebookOutputs: false,
showMinRUSurvey: false,
ttl90Days: false,
enableThroughputCap: false,
@@ -43,7 +43,6 @@ describe("AuthorizationUtils", () => {
partitionKeyDefault: false,
partitionKeyDefault2: false,
notebooksDownBanner: false,
enableRestoreContainer: false,
},
});
};

View File

@@ -8,8 +8,6 @@ import * as Logger from "../Common/Logger";
import { configContext } from "../ConfigContext";
import { DatabaseAccount } from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels";
import { isExpectedError } from "../Metrics/ErrorClassification";
import { scenarioMonitor } from "../Metrics/ScenarioMonitor";
import { trace, traceFailure } from "../Shared/Telemetry/TelemetryProcessor";
import { UserContext, userContext } from "../UserContext";
@@ -129,10 +127,6 @@ export async function acquireMsalTokenForAccount(
acquireTokenType: silent ? "silent" : "interactive",
errorMessage: JSON.stringify(error),
});
// Mark expected failure for health metrics so timeout emits healthy
if (isExpectedError(error)) {
scenarioMonitor.markExpectedFailure();
}
throw error;
}
} else {
@@ -175,10 +169,7 @@ export async function acquireTokenWithMsal(
acquireTokenType: "interactive",
errorMessage: JSON.stringify(interactiveError),
});
// Mark expected failure for health metrics so timeout emits healthy
if (isExpectedError(interactiveError)) {
scenarioMonitor.markExpectedFailure();
}
throw interactiveError;
}
} else {
@@ -187,10 +178,7 @@ export async function acquireTokenWithMsal(
acquireTokenType: "silent",
errorMessage: JSON.stringify(silentError),
});
// Mark expected failure for health metrics so timeout emits healthy
if (isExpectedError(silentError)) {
scenarioMonitor.markExpectedFailure();
}
throw silentError;
}
}

View File

@@ -4,12 +4,7 @@ import * as sinon from "sinon";
import * as DataModels from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels";
import * as QueryUtils from "./QueryUtils";
import {
defaultQueryFields,
extractPartitionKeyValues,
getValueForPath,
stripDoubleQuotesFromSegment,
} from "./QueryUtils";
import { defaultQueryFields, extractPartitionKeyValues, getValueForPath } from "./QueryUtils";
const documentContent = {
"Volcano Name": "Adams",
@@ -284,97 +279,5 @@ describe("Query Utils", () => {
expect(partitionKeyValues.length).toBe(2);
expect(partitionKeyValues).toEqual([null, {}]);
});
it("should extract partition key value when path has enclosing double quotes", () => {
const docWithSpecialKey = {
id: "test-id",
"partition-key": "some-value",
};
const partitionKeyDefinition: PartitionKeyDefinition = {
kind: PartitionKeyKind.Hash,
paths: ['/"partition-key"'],
};
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(docWithSpecialKey, partitionKeyDefinition);
expect(partitionKeyValues.length).toBe(1);
expect(partitionKeyValues[0]).toEqual("some-value");
});
it("should extract nested partition key value when path segments have enclosing double quotes", () => {
const docWithSpecialKey = {
id: "test-id",
"my-field": {
"sub-field": 42,
},
};
const partitionKeyDefinition: PartitionKeyDefinition = {
kind: PartitionKeyKind.Hash,
paths: ['/"my-field"/"sub-field"'],
};
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(docWithSpecialKey, partitionKeyDefinition);
expect(partitionKeyValues.length).toBe(1);
expect(partitionKeyValues[0]).toEqual(42);
});
it("should return {} for missing double-quoted partition key", () => {
const docWithSpecialKey = {
id: "test-id",
};
const partitionKeyDefinition: PartitionKeyDefinition = {
kind: PartitionKeyKind.Hash,
paths: ['/"partition-key"'],
};
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(docWithSpecialKey, partitionKeyDefinition);
expect(partitionKeyValues.length).toBe(1);
expect(partitionKeyValues[0]).toEqual({});
});
it("should handle multi-hash with mixed quoted and unquoted paths", () => {
const doc = {
id: "test-id",
Country: "Japan",
"partition-key": "hello",
};
const partitionKeyDefinition: PartitionKeyDefinition = {
kind: PartitionKeyKind.MultiHash,
paths: ["/Country", '/"partition-key"'],
};
const partitionKeyValues: PartitionKey[] = extractPartitionKeyValues(doc, partitionKeyDefinition);
expect(partitionKeyValues.length).toBe(2);
expect(partitionKeyValues).toEqual(["Japan", "hello"]);
});
});
describe("stripDoubleQuotesFromSegment", () => {
it("should strip enclosing double quotes", () => {
expect(stripDoubleQuotesFromSegment('"partition-key"')).toBe("partition-key");
});
it("should not strip if only opening quote", () => {
expect(stripDoubleQuotesFromSegment('"partition-key')).toBe('"partition-key');
});
it("should not strip if only closing quote", () => {
expect(stripDoubleQuotesFromSegment('partition-key"')).toBe('partition-key"');
});
it("should return empty string when stripping quotes from empty quoted string", () => {
expect(stripDoubleQuotesFromSegment('""')).toBe("");
});
it("should not modify unquoted segments", () => {
expect(stripDoubleQuotesFromSegment("Country")).toBe("Country");
});
it("should not strip single quotes", () => {
expect(stripDoubleQuotesFromSegment("'partition-key'")).toBe("'partition-key'");
});
});
});

View File

@@ -116,17 +116,6 @@ export const queryPagesUntilContentPresent = async (
return await doRequest(firstItemIndex);
};
/**
* Strips enclosing double quotes from a partition key path segment.
* e.g., '"partition-key"' -> 'partition-key'
*/
export const stripDoubleQuotesFromSegment = (segment: string): string => {
if (segment.length >= 2 && segment.charAt(0) === '"' && segment.charAt(segment.length - 1) === '"') {
return segment.slice(1, -1);
}
return segment;
};
/* eslint-disable @typescript-eslint/no-explicit-any */
export const getValueForPath = (content: any, pathSegments: string[]): any => {
if (pathSegments.length === 0) {
@@ -157,7 +146,7 @@ export const extractPartitionKeyValues = (
const partitionKeyValues: PartitionKey[] = [];
partitionKeyDefinition.paths.forEach((partitionKeyPath: string) => {
const pathSegments: string[] = partitionKeyPath.substring(1).split("/").map(stripDoubleQuotesFromSegment);
const pathSegments: string[] = partitionKeyPath.substring(1).split("/");
const value = getValueForPath(documentContent, pathSegments);
if (value !== undefined) {

View File

@@ -1,21 +1,16 @@
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import resourcesToBackend from "i18next-resources-to-backend";
import { initReactI18next } from "react-i18next";
i18n
.use(LanguageDetector)
.use(resourcesToBackend((lng: string, ns: string) => import(`./Localization/${lng}/${ns}.json`)))
.use(initReactI18next)
.init({
fallbackLng: "en",
defaultNS: "Resources",
ns: ["Resources"],
detection: { order: ["navigator", "cookie", "localStorage", "sessionStorage", "querystring", "htmlTag"] },
debug: process.env.NODE_ENV === "development",
keySeparator: ".",
interpolation: {
escapeValue: false,
formatSeparator: ",",
},
react: {

View File

@@ -4,14 +4,9 @@ import Adapter from "enzyme-adapter-react-16";
import "jest-canvas-mock";
import enableHooks from "jest-react-hooks-shallow";
import { TextDecoder, TextEncoder } from "util";
import i18n from "./i18n";
import enResources from "./Localization/en/Resources.json";
configure({ adapter: new Adapter() });
initializeIcons();
// Load English translations synchronously so t() returns real values in tests
i18n.addResourceBundle("en", "Resources", enResources, true, true);
if (typeof window.URL.createObjectURL === "undefined") {
Object.defineProperty(window.URL, "createObjectURL", { value: () => {} });
}

View File

@@ -2,54 +2,20 @@ import { Page } from "@playwright/test";
export async function setupCORSBypass(page: Page) {
await page.route("**/api/mongo/explorer{,/**}", async (route) => {
const request = route.request();
const origin = request.headers()["origin"];
// If there's no origin, it's not a CORS request. Let it proceed without modification.
if (!origin) {
await route.continue();
return;
}
//// Handle preflight (OPTIONS) requests separately.
// These should not be forwarded to the target server.
if (request.method() === "OPTIONS") {
await route.fulfill({
status: 204, // No Content
headers: {
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS,HEAD",
"Access-Control-Request-Headers": "*, x-ms-continuation",
"Access-Control-Max-Age": "86400", // Cache preflight response for 1 day
Vary: "Origin",
},
});
return;
}
// Handle the actual GET/POST request
const response = await route.fetch({
headers: {
...request.headers(),
...route.request().headers(),
},
});
const responseHeaders = response.headers();
// Clean up any pre-existing CORS headers from the real response to avoid conflicts.
delete responseHeaders["access-control-allow-origin"];
delete responseHeaders["access-control-allow-credentials"];
await route.fulfill({
status: response.status(),
headers: {
...responseHeaders,
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS,HEAD",
...response.headers(),
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Expose-Headers": "x-ms-continuation,x-ms-request-charge,x-ms-session-token",
Vary: "Origin",
"Access-Control-Allow-Credentials": "*",
},
body: await response.body(),
});

View File

@@ -58,9 +58,7 @@ export const defaultAccounts: Record<TestAccount, string> = {
export const resourceGroupName = process.env.DE_TEST_RESOURCE_GROUP ?? "de-e2e-tests";
export const subscriptionId = process.env.DE_TEST_SUBSCRIPTION_ID ?? "69e02f2d-f059-4409-9eac-97e8a276ae2c";
export const TEST_AUTOSCALE_THROUGHPUT_RU = 1000;
export const TEST_MANUAL_THROUGHPUT_RU = 800;
export const TEST_AUTOSCALE_MAX_THROUGHPUT_RU_2K = 2000;
export const TEST_AUTOSCALE_MAX_THROUGHPUT_RU_4K = 4000;
export const TEST_MANUAL_THROUGHPUT_RU_2K = 2000;
export const ONE_MINUTE_MS: number = 60 * 1000;
@@ -250,7 +248,7 @@ class TreeNode {
// Try three times to wait for the node to expand.
for (let i = 0; i < RETRY_COUNT; i++) {
try {
await tree.waitFor({ state: "visible", timeout: 30000 });
await tree.waitFor({ state: "visible" });
// The tree has expanded, let's get out of here
return true;
} catch {
@@ -380,11 +378,9 @@ type PanelOpenOptions = {
export enum CommandBarButton {
Save = "Save",
Delete = "Delete",
Execute = "Execute",
ExecuteQuery = "Execute Query",
UploadItem = "Upload Item",
NewDocument = "New Document",
}
/** Helper class that provides locator methods for DataExplorer components, on top of a Frame */
@@ -482,7 +478,7 @@ export class DataExplorer {
return await this.waitForNode(`${databaseId}/${containerId}/Documents`);
}
async waitForCommandBarButton(label: CommandBarButton, timeout?: number): Promise<Locator> {
async waitForCommandBarButton(label: string, timeout?: number): Promise<Locator> {
const commandBar = this.commandBarButton(label);
await commandBar.waitFor({ state: "visible", timeout });
return commandBar;
@@ -519,6 +515,15 @@ export class DataExplorer {
const containerNode = await this.waitForContainerNode(context.database.id, context.container.id);
await containerNode.expand();
// refresh tree to remove deleted database
const consoleMessages = await this.getNotificationConsoleMessages();
const refreshButton = this.frame.getByTestId("Sidebar/RefreshButton");
await refreshButton.click();
await expect(consoleMessages).toContainText("Successfully refreshed databases", {
timeout: ONE_MINUTE_MS,
});
await this.collapseNotificationConsole();
const scaleAndSettingsButton = this.frame.getByTestId(
`TreeNode:${context.database.id}/${context.container.id}/Scale & Settings`,
);

View File

@@ -1,7 +1,7 @@
import { expect, test } from "@playwright/test";
import { setupCORSBypass } from "../CORSBypass";
import { CommandBarButton, DataExplorer, DocumentsTab, TestAccount } from "../fx";
import { DataExplorer, DocumentsTab, TestAccount } from "../fx";
import { retry, serializeMongoToJson, setPartitionKeys } from "../testData";
import { documentTestCases } from "./testCases";
@@ -48,20 +48,19 @@ for (const { name, databaseId, containerId, documents } of documentTestCases) {
expect(resultData?._id).not.toBeNull();
expect(resultData?._id).toEqual(docId);
});
test(`should be able to create and delete new document from ${docId}`, async ({ page }) => {
test(`should be able to create and delete new document from ${docId}`, async () => {
const span = documentsTab.documentsListPane.getByText(docId, { exact: true }).nth(0);
await span.waitFor();
await expect(span).toBeVisible();
await span.click();
await page.waitForTimeout(5000); // wait for 5 seconds to ensure document is fully loaded. waitforTimeout is not recommended generally but here we are working around flakiness in the test env
let newDocumentId;
await retry(async () => {
const newDocumentButton = await explorer.waitForCommandBarButton(CommandBarButton.NewDocument, 5000);
const newDocumentButton = await explorer.waitForCommandBarButton("New Document", 5000);
await expect(newDocumentButton).toBeVisible();
await expect(newDocumentButton).toBeEnabled();
await newDocumentButton.click();
await expect(documentsTab.resultsEditor.locator).toBeAttached({ timeout: 60 * 1000 });
newDocumentId = `${Date.now().toString()}-delete`;
@@ -72,9 +71,8 @@ for (const { name, databaseId, containerId, documents } of documentTestCases) {
};
await documentsTab.resultsEditor.setText(JSON.stringify(newDocument));
const saveButton = await explorer.waitForCommandBarButton(CommandBarButton.Save, 5000);
const saveButton = await explorer.waitForCommandBarButton("Save", 5000);
await saveButton.click({ timeout: 5000 });
await expect(saveButton).toBeHidden({ timeout: 5000 });
}, 3);
@@ -86,7 +84,7 @@ for (const { name, databaseId, containerId, documents } of documentTestCases) {
await newSpan.click();
await expect(documentsTab.resultsEditor.locator).toBeAttached({ timeout: 60 * 1000 });
const deleteButton = await explorer.waitForCommandBarButton(CommandBarButton.Delete, 5000);
const deleteButton = await explorer.waitForCommandBarButton("Delete", 5000);
await deleteButton.click();
const deleteDialogButton = await explorer.waitForDialogButton("Delete", 5000);

View File

@@ -1,132 +0,0 @@
import { expect, test } from "@playwright/test";
import { setupCORSBypass } from "../CORSBypass";
import { DataExplorer, QueryTab, TestAccount, CommandBarButton, Editor } from "../fx";
import { serializeMongoToJson } from "../testData";
const databaseId = "test-e2etests-mongo-pagination";
const collectionId = "test-coll-mongo-pagination";
let explorer: DataExplorer = null!;
test.setTimeout(5 * 60 * 1000);
test.describe("Test Mongo Pagination", () => {
let queryTab: QueryTab;
let queryEditor: Editor;
test.beforeEach("Open query tab", async ({ page }) => {
await setupCORSBypass(page);
explorer = await DataExplorer.open(page, TestAccount.MongoReadonly);
const containerNode = await explorer.waitForContainerNode(databaseId, collectionId);
await containerNode.expand();
const containerMenuNode = await explorer.waitForContainerDocumentsNode(databaseId, collectionId);
await containerMenuNode.openContextMenu();
await containerMenuNode.contextMenuItem("New Query").click();
queryTab = explorer.queryTab("tab0");
queryEditor = queryTab.editor();
await queryEditor.locator.waitFor({ timeout: 30 * 1000 });
await queryTab.executeCTA.waitFor();
await explorer.frame.getByTestId("NotificationConsole/ExpandCollapseButton").click();
await explorer.frame.getByTestId("NotificationConsole/Contents").waitFor();
});
test("should execute a query and load more results", async ({ page }) => {
const query = "{}";
await queryEditor.locator.click();
await queryEditor.setText(query);
const executeQueryButton = explorer.commandBarButton(CommandBarButton.ExecuteQuery);
await executeQueryButton.click();
// Wait for query execution to complete
await expect(queryTab.resultsView).toBeVisible({ timeout: 60000 });
await expect(queryTab.resultsEditor.locator).toBeAttached({ timeout: 30000 });
// Get initial results
const resultText = await queryTab.resultsEditor.text();
if (!resultText || resultText.trim() === "" || resultText.trim() === "[]") {
throw new Error("Query returned no results - the collection appears to be empty");
}
const resultData = serializeMongoToJson(resultText);
if (resultData.length === 0) {
throw new Error("Parsed results contain 0 documents - collection is empty");
}
if (resultData.length < 100) {
expect(resultData.length).toBeGreaterThan(0);
return;
}
expect(resultData.length).toBe(100);
// Pagination test
let totalPagesLoaded = 1;
const maxLoadMoreAttempts = 10;
for (let loadMoreAttempts = 0; loadMoreAttempts < maxLoadMoreAttempts; loadMoreAttempts++) {
const loadMoreButton = queryTab.resultsView.getByText("Load more");
try {
await expect(loadMoreButton).toBeVisible({ timeout: 5000 });
} catch {
// Load more button not visible - pagination complete
break;
}
const beforeClickText = await queryTab.resultsEditor.text();
const beforeClickHash = Buffer.from(beforeClickText || "")
.toString("base64")
.substring(0, 50);
await loadMoreButton.click();
// Wait for content to update
let editorContentChanged = false;
for (let waitAttempt = 1; waitAttempt <= 3; waitAttempt++) {
await page.waitForTimeout(2000);
const currentEditorText = await queryTab.resultsEditor.text();
const currentHash = Buffer.from(currentEditorText || "")
.toString("base64")
.substring(0, 50);
if (currentHash !== beforeClickHash) {
editorContentChanged = true;
break;
}
}
if (editorContentChanged) {
totalPagesLoaded++;
} else {
// No content change detected, stop pagination
break;
}
await page.waitForTimeout(1000);
}
// Final verification
const finalIndicator = queryTab.resultsView.locator("text=/\\d+ - \\d+/");
const finalIndicatorText = await finalIndicator.textContent();
if (finalIndicatorText) {
const match = finalIndicatorText.match(/(\d+) - (\d+)/);
if (match) {
const totalDocuments = parseInt(match[2]);
expect(totalDocuments).toBe(405);
expect(totalPagesLoaded).toBe(5);
} else {
throw new Error(`Invalid results indicator format: ${finalIndicatorText}`);
}
} else {
expect(totalPagesLoaded).toBe(5);
}
});
});

View File

@@ -9,10 +9,9 @@ import {
TestAccount,
waitForApiResponse,
} from "../../fx";
import { createMultipleTestContainers, TestContainerContext } from "../../testData";
import { createMultipleTestContainers } from "../../testData";
test.describe("Container Copy - Offline Migration", () => {
let contexts: TestContainerContext[];
let page: Page;
let wrapper: Locator;
let panel: Locator;
@@ -23,7 +22,7 @@ test.describe("Container Copy - Offline Migration", () => {
let expectedCopyJobNameInitial: string;
test.beforeEach("Setup for offline migration test", async ({ browser }) => {
contexts = await createMultipleTestContainers({ accountType: TestAccount.SQLContainerCopyOnly, containerCount: 2 });
await createMultipleTestContainers({ accountType: TestAccount.SQLContainerCopyOnly, containerCount: 2 });
page = await browser.newPage();
({ wrapper, frame } = await ContainerCopy.open(page, TestAccount.SQLContainerCopyOnly));
@@ -34,7 +33,6 @@ test.describe("Container Copy - Offline Migration", () => {
test.afterEach("Cleanup after offline migration test", async () => {
await page.unroute(/.*/, (route) => route.continue());
await page.close();
await Promise.all(contexts.map((context) => context?.dispose()));
});
test("Successfully create and manage offline migration copy job", async () => {
@@ -248,17 +246,13 @@ test.describe("Container Copy - Offline Migration", () => {
expect(response.ok()).toBe(true);
// Verify panel closes and job appears in the list
await expect(panel).not.toBeVisible();
const filterTextField = wrapper.getByTestId("CopyJobsList/FilterTextField");
await filterTextField.waitFor({ state: "visible" });
await filterTextField.fill(validJobName);
await expect(panel).not.toBeVisible({ timeout: 5000 });
const jobsListContainer = wrapper.locator(".CopyJobListContainer .ms-DetailsList-contentWrapper .ms-List-page");
await jobsListContainer.waitFor({ state: "visible" });
await jobsListContainer.waitFor({ state: "visible", timeout: 5000 });
const jobItem = jobsListContainer.getByText(validJobName);
await jobItem.waitFor({ state: "visible" });
await jobItem.waitFor({ state: "visible", timeout: 5000 });
await expect(jobItem).toBeVisible();
});
});

View File

@@ -7,10 +7,9 @@ import {
TestAccount,
waitForApiResponse,
} from "../../fx";
import { createMultipleTestContainers, TestContainerContext } from "../../testData";
import { createMultipleTestContainers } from "../../testData";
test.describe("Container Copy - Online Migration", () => {
let contexts: TestContainerContext[];
let page: Page;
let wrapper: Locator;
let panel: Locator;
@@ -18,7 +17,7 @@ test.describe("Container Copy - Online Migration", () => {
let targetAccountName: string;
test.beforeEach("Setup for online migration test", async ({ browser }) => {
contexts = await createMultipleTestContainers({ accountType: TestAccount.SQLContainerCopyOnly, containerCount: 2 });
await createMultipleTestContainers({ accountType: TestAccount.SQLContainerCopyOnly, containerCount: 2 });
page = await browser.newPage();
({ wrapper, frame } = await ContainerCopy.open(page, TestAccount.SQLContainerCopyOnly));
@@ -28,7 +27,6 @@ test.describe("Container Copy - Online Migration", () => {
test.afterEach("Cleanup after online migration test", async () => {
await page.unroute(/.*/, (route) => route.continue());
await page.close();
await Promise.all(contexts.map((context) => context?.dispose()));
});
test("Successfully create and manage online migration copy job", async () => {
@@ -122,22 +120,18 @@ test.describe("Container Copy - Online Migration", () => {
expect(response.ok()).toBe(true);
// Verify panel closes and job appears in the list
await expect(panel).not.toBeVisible();
const filterTextField = wrapper.getByTestId("CopyJobsList/FilterTextField");
await filterTextField.waitFor({ state: "visible" });
await filterTextField.fill(onlineMigrationJobName);
await expect(panel).not.toBeVisible({ timeout: 5000 });
const jobsListContainer = wrapper.locator(".CopyJobListContainer .ms-DetailsList-contentWrapper .ms-List-page");
await jobsListContainer.waitFor({ state: "visible" });
await jobsListContainer.waitFor({ state: "visible", timeout: 5000 });
let jobRow, statusCell, actionMenuButton;
jobRow = jobsListContainer.locator(".ms-DetailsRow", { hasText: onlineMigrationJobName });
statusCell = jobRow.locator("[data-automationid='DetailsRowCell'][data-automation-key='CopyJobStatus']");
await jobRow.waitFor({ state: "visible" });
await jobRow.waitFor({ state: "visible", timeout: 5000 });
// Verify job status changes to queued state
await expect(statusCell).toContainText(/running|queued|pending/i);
await expect(statusCell).toContainText(/running|queued|pending/i, { timeout: 5000 });
// Test job lifecycle management through action menu
actionMenuButton = wrapper.getByTestId(`CopyJobActionMenu/Button:${onlineMigrationJobName}`);

View File

@@ -134,7 +134,7 @@ test.describe("Container Copy - Permission Screen Verification", () => {
const pitrBtn = accordionPanel.getByTestId("pointInTimeRestore:PrimaryBtn");
await expect(pitrBtn).toBeVisible();
await pitrBtn.click({ force: true });
await pitrBtn.click();
// Verify new page opens with correct URL pattern
page.context().on("page", async (newPage) => {
@@ -246,7 +246,7 @@ test.describe("Container Copy - Permission Screen Verification", () => {
const toggleButton = crossAccordionPanel.getByTestId("btn-toggle");
await expect(toggleButton).toBeVisible();
await toggleButton.click({ force: true });
await toggleButton.click();
// Verify popover functionality
const popover = frame.locator("[data-test='popover-container']");
@@ -257,7 +257,7 @@ test.describe("Container Copy - Permission Screen Verification", () => {
await expect(yesButton).toBeVisible();
await expect(noButton).toBeVisible();
await yesButton.click({ force: true });
await yesButton.click();
// Verify loading states
await expect(loadingOverlay).toBeVisible();
@@ -265,6 +265,6 @@ test.describe("Container Copy - Permission Screen Verification", () => {
await expect(popover).toBeHidden({ timeout: 10 * 1000 });
// Cancel the panel to clean up
await panel.getByRole("button", { name: "Cancel" }).click({ force: true });
await panel.getByRole("button", { name: "Cancel" }).click();
});
});

View File

@@ -136,7 +136,9 @@ test.describe.serial("Upload Item", () => {
if (existsSync(uploadDocumentDirPath)) {
rmdirSync(uploadDocumentDirPath);
}
await context?.dispose();
if (!process.env.CI) {
await context?.dispose();
}
});
test.afterEach("Close Upload Items panel if still open", async () => {

View File

@@ -10,7 +10,7 @@ let CONTAINER_ID: string;
// Set up test database and container with data before all tests
test.beforeAll(async () => {
testContainer = await createTestSQLContainer({ includeTestData: true });
testContainer = await createTestSQLContainer(true);
DATABASE_ID = testContainer.database.id;
CONTAINER_ID = testContainer.container.id;
});

View File

@@ -30,9 +30,12 @@ test.beforeEach("Open new query tab", async ({ page }) => {
await explorer.frame.getByTestId("NotificationConsole/Contents").waitFor();
});
test.afterAll("Delete Test Database", async () => {
await context?.dispose();
});
// Delete database only if not running in CI
if (!process.env.CI) {
test.afterAll("Delete Test Database", async () => {
await context?.dispose();
});
}
test("Query results", async () => {
// Run the query and verify the results

View File

@@ -2,6 +2,7 @@ import { expect, test } from "@playwright/test";
import { CosmosDBManagementClient } from "@azure/arm-cosmosdb";
import { CosmosClient, PermissionMode } from "@azure/cosmos";
import { AzureIdentityCredentialAdapter } from "@azure/ms-rest-js";
import {
DataExplorer,
TestAccount,
@@ -17,7 +18,8 @@ test("SQL account using Resource token", async ({ page }) => {
test.skip(nosqlAccountRbacToken.length > 0, "Resource tokens not supported when using data plane RBAC.");
const credentials = getAzureCLICredentials();
const armClient = new CosmosDBManagementClient(credentials, subscriptionId);
const adaptedCredentials = new AzureIdentityCredentialAdapter(credentials);
const armClient = new CosmosDBManagementClient(adaptedCredentials, subscriptionId);
const accountName = getAccountName(TestAccount.SQL);
const account = await armClient.databaseAccounts.get(resourceGroupName, accountName);
const keys = await armClient.databaseAccounts.listKeys(resourceGroupName, accountName);

View File

@@ -23,9 +23,12 @@ test.describe("Change Partition Key", () => {
await PartitionKeyTab.click();
});
test.afterEach("Delete Test Database", async () => {
await context?.dispose();
});
// Delete database only if not running in CI
if (!process.env.CI) {
test.afterEach("Delete Test Database", async () => {
await context?.dispose();
});
}
test("Change partition key path", async ({ page }) => {
await expect(explorer.frame.getByText("/partitionKey")).toBeVisible();

View File

@@ -1,127 +0,0 @@
import { expect, test, type Page } from "@playwright/test";
import { DataExplorer, TestAccount } from "../../fx";
import { createTestSQLContainer, TestContainerContext } from "../../testData";
/**
* Tests for Dynamic Data Masking (DDM) feature.
*
* Prerequisites:
* - Test account must have the EnableDynamicDataMasking capability enabled
* - If the capability is not enabled, the DataMaskingTab will not be visible and tests will be skipped
*
* Important Notes:
* - Tests focus on enabling DDM and modifying the masking policy configuration
*/
let testContainer: TestContainerContext;
let DATABASE_ID: string;
let CONTAINER_ID: string;
test.beforeAll(async () => {
testContainer = await createTestSQLContainer();
DATABASE_ID = testContainer.database.id;
CONTAINER_ID = testContainer.container.id;
});
// Clean up test database after all tests
test.afterAll(async () => {
if (testContainer) {
await testContainer.dispose();
}
});
// Helper function to navigate to Data Masking tab
async function navigateToDataMaskingTab(page: Page, explorer: DataExplorer): Promise<boolean> {
// Refresh the tree to see the newly created database
const refreshButton = explorer.frame.getByTestId("Sidebar/RefreshButton");
await refreshButton.click();
await page.waitForTimeout(3000);
// Expand database and container nodes
const databaseNode = await explorer.waitForNode(DATABASE_ID);
await databaseNode.expand();
await page.waitForTimeout(2000);
const containerNode = await explorer.waitForNode(`${DATABASE_ID}/${CONTAINER_ID}`);
await containerNode.expand();
await page.waitForTimeout(1000);
// Click Scale & Settings or Settings (depending on container type)
let settingsNode = explorer.frame.getByTestId(`TreeNode:${DATABASE_ID}/${CONTAINER_ID}/Scale & Settings`);
const isScaleAndSettings = await settingsNode.isVisible().catch(() => false);
if (!isScaleAndSettings) {
settingsNode = explorer.frame.getByTestId(`TreeNode:${DATABASE_ID}/${CONTAINER_ID}/Settings`);
}
await settingsNode.click();
await page.waitForTimeout(2000);
// Check if Data Masking tab is available
const dataMaskingTab = explorer.frame.getByTestId("settings-tab-header/DataMaskingTab");
const isTabVisible = await dataMaskingTab.isVisible().catch(() => false);
if (!isTabVisible) {
return false;
}
await dataMaskingTab.click();
await page.waitForTimeout(1000);
return true;
}
test.describe("Data Masking under Scale & Settings", () => {
test("Data Masking tab should be visible and show JSON editor", async ({ page }) => {
const explorer = await DataExplorer.open(page, TestAccount.SQL);
const isTabAvailable = await navigateToDataMaskingTab(page, explorer);
if (!isTabAvailable) {
test.skip(
true,
"Data Masking tab is not available. Test account may not have EnableDynamicDataMasking capability.",
);
}
// Verify the Data Masking editor is visible
const dataMaskingEditor = explorer.frame.locator(".settingsV2Editor");
await expect(dataMaskingEditor).toBeVisible();
});
test("Data Masking editor should contain default policy structure", async ({ page }) => {
const explorer = await DataExplorer.open(page, TestAccount.SQL);
const isTabAvailable = await navigateToDataMaskingTab(page, explorer);
if (!isTabAvailable) {
test.skip(
true,
"Data Masking tab is not available. Test account may not have EnableDynamicDataMasking capability.",
);
}
// Verify the editor contains the expected JSON structure fields
const editorContent = explorer.frame.locator(".settingsV2Editor");
await expect(editorContent).toBeVisible();
// Check that the editor contains key policy fields (default policy has empty arrays)
await expect(editorContent).toContainText("includedPaths");
await expect(editorContent).toContainText("excludedPaths");
});
test("Data Masking editor should have correct default policy values", async ({ page }) => {
const explorer = await DataExplorer.open(page, TestAccount.SQL);
const isTabAvailable = await navigateToDataMaskingTab(page, explorer);
if (!isTabAvailable) {
test.skip(
true,
"Data Masking tab is not available. Test account may not have EnableDynamicDataMasking capability.",
);
}
const editorContent = explorer.frame.locator(".settingsV2Editor");
await expect(editorContent).toBeVisible();
// Default policy should have empty includedPaths and excludedPaths arrays
await expect(editorContent).toContainText("[]");
});
});

View File

@@ -118,5 +118,7 @@ async function openScaleTab(browser: Browser): Promise<SetupResult> {
}
async function cleanup({ context }: Partial<SetupResult>) {
await context?.dispose();
if (!process.env.CI) {
await context?.dispose();
}
}

View File

@@ -17,9 +17,12 @@ test.describe("Settings under Scale & Settings", () => {
await settingsTab.click();
});
test.afterAll("Delete Test Database", async () => {
await context?.dispose();
});
// Delete database only if not running in CI
if (!process.env.CI) {
test.afterAll("Delete Test Database", async () => {
await context?.dispose();
});
}
test("Update TTL to On (no default)", async () => {
const ttlOnNoDefaultRadioButton = explorer.frame.getByRole("radio", { name: "ttl-on-no-default-option" });

Some files were not shown because too many files have changed in this diff Show More