Remove Phoenix and notebooks (Phase 6)

Complete the final removal phase by deleting Juno and analytical schema integration, residual Phoenix and notebook contracts, configuration, localization, and assets. Preserve CloudShell behavior and numeric compatibility contracts while cleaning stale UI terminology.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8730a951-831c-4cc2-9c91-83e237683d46
This commit is contained in:
Jade Welton
2026-08-27 13:59:10 -07:00
parent f30a613ab3
commit 78d0d8deef
108 changed files with 154 additions and 2570 deletions
-67
View File
@@ -33,7 +33,6 @@ export class ArmApiVersions {
}
export class ArmResourceTypes {
public static readonly notebookWorkspaces = "Microsoft.DocumentDB/databaseAccounts/notebookWorkspaces";
public static readonly synapseWorkspaces = "Microsoft.Synapse/workspaces";
}
@@ -78,7 +77,6 @@ export class CapabilityNames {
public static EnableGremlin: string = "EnableGremlin";
public static EnableCassandra: string = "EnableCassandra";
public static EnableAutoScale: string = "EnableAutoScale";
public static readonly EnableNotebooks: string = "EnableNotebooks";
public static readonly EnableStorageAnalytics: string = "EnableStorageAnalytics";
public static readonly EnableMongo: string = "EnableMongo";
public static readonly EnableServerless: string = "EnableServerless";
@@ -109,14 +107,10 @@ export class Flights {
public static readonly AutoscaleTest = "autoscaletest";
public static readonly PartitionKeyTest = "partitionkeytest";
public static readonly PKPartitionKeyTest = "pkpartitionkeytest";
public static readonly PhoenixNotebooks = "phoenixnotebooks";
public static readonly PhoenixFeatures = "phoenixfeatures";
public static readonly NotebooksDownBanner = "notebooksdownbanner";
}
export class AfecFeatures {
public static readonly Spark = "spark-public-preview";
public static readonly Notebooks = "sparknotebooks-public-preview";
public static readonly StorageAnalytics = "storageanalytics-public-preview";
}
@@ -251,7 +245,6 @@ export class Areas {
public static ContextualPane: string = "Contextual Pane";
public static Tab: string = "Tab";
public static ShareDialog: string = "Share Access Dialog";
public static Notebook: string = "Notebook";
public static CloudShell: string = "Cloud Shell";
}
@@ -433,62 +426,10 @@ export enum ConflictOperationType {
Delete = "delete",
}
export enum ConnectionStatusType {
Connect = "Connect",
Connecting = "Connecting",
Connected = "Connected",
Failed = "Connection Failed",
Reconnect = "Reconnect",
}
export enum ContainerStatusType {
Active = "Active",
Disconnected = "Disconnected",
}
export enum PoolIdType {
DefaultPoolId = "default",
}
export const EmulatorMasterKey =
//[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Well known public masterKey for emulator")]
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
export class Notebook {
public static readonly defaultBasePath = "./notebooks";
public static readonly heartbeatDelayMs = 60000;
public static readonly containerStatusHeartbeatDelayMs = 30000;
public static readonly kernelRestartInitialDelayMs = 1000;
public static readonly kernelRestartMaxDelayMs = 20000;
public static readonly autoSaveIntervalMs = 300000;
public static readonly memoryGuageToGB = 1048576;
public static readonly lowMemoryThreshold = 0.8;
public static readonly remainingTimeForAlert = 10;
public static readonly retryAttempts = 3;
public static readonly retryAttemptDelayMs = 5000;
public static readonly temporarilyDownMsg = "Notebooks is currently not available. We are working on it.";
public static readonly mongoShellTemporarilyDownMsg =
"We have identified an issue with the Mongo Shell and it is unavailable right now. We are actively working on the mitigation.";
public static readonly cassandraShellTemporarilyDownMsg =
"We have identified an issue with the Cassandra Shell and it is unavailable right now. We are actively working on the mitigation.";
public static saveNotebookModalTitle = "Save notebook in temporary workspace";
public static saveNotebookModalContent =
"This notebook will be saved in the temporary workspace and will be removed when the session expires.";
public static newNotebookModalTitle = "Create notebook in temporary workspace";
public static newNotebookUploadModalTitle = "Upload notebook to temporary workspace";
public static newNotebookModalContent1 =
"A temporary workspace will be created to enable you to work with notebooks. When the session expires, any notebooks in the workspace will be removed.";
public static newNotebookModalContent2 =
"To save your work permanently, save your notebooks to a GitHub repository or download the notebooks to your local machine before the session ends. ";
public static galleryNotebookDownloadContent1 =
"To download, run, and make changes to this sample notebook, a temporary workspace will be created. When the session expires, any notebooks in the workspace will be removed.";
public static galleryNotebookDownloadContent2 =
"To save your work permanently, save your notebooks to a GitHub repository or download the Notebooks to your local machine before the session ends. ";
public static cosmosNotebookHomePageUrl = "https://aka.ms/cosmos-notebooks-limits";
public static cosmosNotebookGitDocumentationUrl = "https://aka.ms/cosmos-notebooks-github";
public static learnMore = "Learn more.";
}
export class SparkLibrary {
public static readonly nameMinLength = 3;
public static readonly nameMaxLength = 63;
@@ -508,14 +449,6 @@ export class TerminalQueryParams {
public static readonly TerminalEndpoint = "terminalEndpoint";
}
export class JunoEndpoints {
public static readonly Test = "https://juno-test.documents-dev.windows-int.net";
public static readonly Test2 = "https://juno-test2.documents-dev.windows-int.net";
public static readonly Test3 = "https://juno-test3.documents-dev.windows-int.net";
public static readonly Prod = "https://tools.cosmos.azure.com";
public static readonly Stage = "https://tools-staging.cosmos.azure.com";
}
export class PriorityLevel {
public static readonly High = "high";
public static readonly Low = "low";
+1 -1
View File
@@ -89,7 +89,7 @@ export const Upload: FunctionComponent<UploadProps> = ({
onChange={onUpload}
role="button"
/>
<a href="#" id="fileImportLinkNotebook" onClick={onImportLinkClick} onKeyPress={onImportLinkKeyPress}>
<a href="#" id="fileImportLink" onClick={onImportLinkClick} onKeyPress={onImportLinkKeyPress}>
<Image className="fileImportImg" src={FolderIcon} alt={title} title={title} />
</a>
</Stack>
+1 -10
View File
@@ -1,9 +1,8 @@
import { CassandraProxyEndpoints, JunoEndpoints, MongoProxyEndpoints, PortalBackendEndpoints } from "Common/Constants";
import { CassandraProxyEndpoints, MongoProxyEndpoints, PortalBackendEndpoints } from "Common/Constants";
import {
allowedArcadiaEndpoints,
allowedEmulatorEndpoints,
allowedHostedExplorerEndpoints,
allowedJunoOrigins,
allowedMsalRedirectEndpoints,
defaultAllowedAadEndpoints,
defaultAllowedArmEndpoints,
@@ -47,8 +46,6 @@ export interface ConfigContext {
MONGO_PROXY_ENDPOINT: string;
CASSANDRA_PROXY_ENDPOINT: string;
PROXY_PATH?: string;
JUNO_ENDPOINT: string;
isPhoenixEnabled: boolean;
hostedExplorerURL: string;
armAPIVersion?: string;
msalRedirectURI?: string;
@@ -92,11 +89,9 @@ let configContext: Readonly<ConfigContext> = {
CATALOG_API_KEY: "",
ARCADIA_ENDPOINT: "https://workspaceartifacts.projectarcadia.net",
ARCADIA_LIVY_ENDPOINT_DNS_ZONE: "dev.azuresynapse.net",
JUNO_ENDPOINT: JunoEndpoints.Prod,
PORTAL_BACKEND_ENDPOINT: PortalBackendEndpoints.Prod,
MONGO_PROXY_ENDPOINT: MongoProxyEndpoints.Prod,
CASSANDRA_PROXY_ENDPOINT: CassandraProxyEndpoints.Prod,
isPhoenixEnabled: false,
};
export function resetConfigContext(): void {
@@ -162,10 +157,6 @@ export function updateConfigContext(newContext: Partial<ConfigContext>): void {
delete newContext.CASSANDRA_PROXY_ENDPOINT;
}
if (!validateEndpoint(newContext.JUNO_ENDPOINT, allowedJunoOrigins)) {
delete newContext.JUNO_ENDPOINT;
}
if (!validateEndpoint(newContext.hostedExplorerURL, allowedHostedExplorerEndpoints)) {
delete newContext.hostedExplorerURL;
}
+7 -13
View File
@@ -2,14 +2,13 @@
* Data Explorer tab kinds
*/
export enum TabKind {
SQLDocuments,
MongoDocuments,
SchemaAnalyzer,
TableEntities,
Graph,
SQLQuery,
ScaleSettings,
MongoQuery,
SQLDocuments = 0,
MongoDocuments = 1,
TableEntities = 3,
Graph = 4,
SQLQuery = 5,
ScaleSettings = 6,
MongoQuery = 7,
}
/**
@@ -72,10 +71,6 @@ export interface OpenPane extends DataExplorerAction {
paneKind: PaneKind | string;
}
export interface OpenSampleNotebook extends DataExplorerAction {
path: string;
}
/**
* The types of actions that the DataExplorer supports performing upon opening.
*/
@@ -84,5 +79,4 @@ export enum ActionType {
OpenCollectionTab,
OpenPane,
TransmitCachedData,
OpenSampleNotebook,
}
+1 -140
View File
@@ -1,4 +1,4 @@
import { CapacityMode, ConnectionStatusType, ContainerStatusType } from "../Common/Constants";
import { CapacityMode } from "../Common/Constants";
export interface ArmEntity {
id: string;
@@ -155,38 +155,6 @@ export interface Resource {
id: string;
}
export interface IType {
name: string;
code: number;
}
export interface IDataField {
dataType: IType;
hasNulls: boolean;
isArray: boolean;
schemaType: IType;
name: string;
path: string;
maxRepetitionLevel: number;
maxDefinitionLevel: number;
}
export interface ISchema {
id: string;
accountName: string;
resource: string;
fields: IDataField[];
}
export interface ISchemaRequest {
id: string;
subscriptionId: string;
resourceGroup: string;
accountName: string;
resource: string;
status: string;
}
export interface Collection extends Resource {
// Only in Mongo collections loaded via ARM
shardKey?: {
@@ -204,8 +172,6 @@ export interface Collection extends Resource {
vectorEmbeddingPolicy?: VectorEmbeddingPolicy;
fullTextPolicy?: FullTextPolicy;
dataMaskingPolicy?: DataMaskingPolicy;
schema?: ISchema;
requestSchema?: () => void;
computedProperties?: ComputedProperties;
materializedViews?: MaterializedView[];
materializedViewDefinition?: MaterializedViewDefinition;
@@ -588,89 +554,6 @@ export interface OperationStatus {
error?: { code: string; message: string };
}
export interface NotebookWorkspaceConnectionInfo {
authToken: string;
notebookServerEndpoint: string;
forwardingId: string;
}
export interface ContainerInfo {
durationLeftInMinutes: number;
phoenixServerInfo: NotebookWorkspaceConnectionInfo;
status: ContainerStatusType;
}
export interface IProvisionData {
cosmosEndpoint?: string;
poolId: string;
databaseId?: string;
containerId?: string;
mode?: string;
}
export interface IContainerData {
forwardingId: string;
}
export interface IResponse<T> {
status: number;
data: T;
}
export interface IPhoenixError {
message: string;
type: string;
}
export interface IMaxAllocationTimeExceeded extends IPhoenixError {
earliestAllocationTimestamp: string;
maxAllocationTimePerDayPerUserInMinutes: string;
}
export interface IMaxDbAccountsPerUserExceeded extends IPhoenixError {
maxSimultaneousConnectionsPerUser: string;
}
export interface IMaxUsersPerDbAccountExceeded extends IPhoenixError {
maxSimultaneousUsersPerDbAccount: string;
}
export interface IPhoenixConnectionInfoResult {
readonly phoenixServiceInfo?: IPhoenixServiceInfo;
}
export interface IPhoenixServiceInfo {
readonly authToken?: string;
readonly phoenixServiceUrl?: string;
readonly forwardingId?: string;
}
export interface NotebookWorkspaceFeedResponse {
value: NotebookWorkspace[];
}
export interface NotebookWorkspace {
id: string;
name: string;
properties: {
status: string;
notebookServerEndpoint: string;
};
}
export interface NotebookConfigurationEndpoints {
path: string;
endpoints: NotebookConfigurationEndpointInfo[];
}
export interface NotebookConfigurationEndpointInfo {
type: string;
endpoint: string;
username: string;
password: string;
token: string;
}
export interface SparkClusterConnectionInfo {
userName: string;
password: string;
@@ -711,16 +594,6 @@ export interface MongoParameters extends RpParameters {
analyticalStorageTtl?: number;
}
export interface MemoryUsageInfo {
freeKB: number;
totalKB: number;
}
export interface ContainerConnectionInfo {
status: ConnectionStatusType;
//need to add ram and rom info
}
export interface FirewallRule {
id: string;
name: string;
@@ -731,18 +604,6 @@ export interface FirewallRule {
};
}
export enum PhoenixErrorType {
MaxAllocationTimeExceeded = "MaxAllocationTimeExceeded",
MaxDbAccountsPerUserExceeded = "MaxDbAccountsPerUserExceeded",
MaxUsersPerDbAccountExceeded = "MaxUsersPerDbAccountExceeded",
AllocationValidationResult = "AllocationValidationResult",
RegionNotServicable = "RegionNotServicable",
SubscriptionNotAllowed = "SubscriptionNotAllowed",
UnknownError = "UnknownError",
PhoenixFlightFallback = "PhoenixFlightFallback",
UserMissingPermissionsError = "UserMissingPermissionsError",
}
export interface FeatureRegistration {
name: string;
properties: {
-8
View File
@@ -136,8 +136,6 @@ export interface CollectionBase extends TreeNode {
export interface Collection extends CollectionBase {
defaultTtl: ko.Observable<number>;
analyticalStorageTtl: ko.Observable<number>;
schema?: DataModels.ISchema;
requestSchema?: () => void;
vectorEmbeddingPolicy: ko.Observable<DataModels.VectorEmbeddingPolicy>;
fullTextPolicy: ko.Observable<DataModels.FullTextPolicy>;
dataMaskingPolicy: ko.Observable<DataModels.DataMaskingPolicy>;
@@ -388,16 +386,10 @@ export enum CollectionTabKind {
MongoShell = 10,
DatabaseSettings = 11,
Conflicts = 12,
Notebook = 13 /* Deprecated */,
Terminal = 14,
NotebookV2 = 15,
SparkMasterTab = 16 /* Deprecated */,
Gallery = 17 /* Deprecated */,
NotebookViewer = 18,
Schema = 19,
CollectionSettingsV2 = 20,
DatabaseSettingsV2 = 21,
SchemaAnalyzer = 22,
}
export enum TerminalKind {
+2 -2
View File
@@ -120,7 +120,7 @@ export const createCollectionContextMenuButton = (
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
if (userContext.features.enableCloudShell) {
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
container.openTerminal(ViewModels.TerminalKind.Mongo);
} else {
selectedCollection && selectedCollection.onNewMongoShellClick();
}
@@ -133,7 +133,7 @@ export const createCollectionContextMenuButton = (
items.push({
iconSrc: HostedTerminalIcon,
onClick: () => {
container.openNotebookTerminal(ViewModels.TerminalKind.Cassandra);
container.openTerminal(ViewModels.TerminalKind.Cassandra);
},
label: t(Keys.contextMenu.openCassandraShell),
});
@@ -60,7 +60,6 @@ export const FeaturePanelComponent: React.FunctionComponent = () => {
value: "true",
},
{ key: "feature.ttl90days", label: "TTL 90 days", value: "true" },
{ key: "feature.enablenotebooks", label: "Enable notebooks", value: "true" },
{
key: "feature.customportal",
label: "Force Production portal (portal only)",
@@ -79,9 +78,6 @@ export const FeaturePanelComponent: React.FunctionComponent = () => {
reactState?: [string, React.Dispatch<React.SetStateAction<string>>];
onChange?: (_: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => void;
}[] = [
{ key: "feature.notebookserverurl", label: "Notebook server URL", placeholder: "https://notebookserver" },
{ key: "feature.notebookservertoken", label: "Notebook server token", placeholder: "" },
{ key: "feature.notebookbasepath", label: "Notebook base path", placeholder: "" },
{ key: "key", label: "Auth key", placeholder: "" },
{
key: "dataExplorerSource",
@@ -131,16 +127,6 @@ export const FeaturePanelComponent: React.FunctionComponent = () => {
}),
);
const onNotebookShortcut = (): void => {
booleanFeatures.find((f) => f.key === "feature.enablenotebooks").reactState[1](true);
stringFeatures
.find((f) => f.key === "feature.notebookserverurl")
.reactState[1]("https://localhost:10001/12345/notebook/");
stringFeatures.find((f) => f.key === "feature.notebookservertoken").reactState[1]("token");
stringFeatures.find((f) => f.key === "feature.notebookbasepath").reactState[1]("./notebooks");
setPlatform(platformOptions.find((o) => o.key === "Hosted"));
};
const onPortalLocalDEShortcut = (): void => {
setBaseUrl(baseUrlOptions.find((o) => o.key === "https://portal.azure.com"));
setPlatform(platformOptions.find((o) => o.key === "Portal"));
@@ -178,7 +164,6 @@ export const FeaturePanelComponent: React.FunctionComponent = () => {
</div>
<Stack className="options" tokens={stackTokens}>
<Stack horizontal horizontalAlign="space-between" tokens={stackTokens}>
<DefaultButton onClick={onNotebookShortcut}>Notebooks on localhost</DefaultButton>
<DefaultButton onClick={onPortalLocalDEShortcut}>Portal points to local DE</DefaultButton>
<DefaultButton onClick={onReset}>Reset</DefaultButton>
</Stack>
@@ -32,11 +32,6 @@ exports[`Feature panel renders all flags 1`] = `
}
}
>
<CustomizedDefaultButton
onClick={[Function]}
>
Notebooks on localhost
</CustomizedDefaultButton>
<CustomizedDefaultButton
onClick={[Function]}
>
@@ -178,12 +173,6 @@ exports[`Feature panel renders all flags 1`] = `
label="TTL 90 days"
onChange={[Function]}
/>
<StyledCheckboxBase
checked={false}
key="feature.enablenotebooks"
label="Enable notebooks"
onChange={[Function]}
/>
<StyledCheckboxBase
checked={false}
disabled={true}
@@ -213,49 +202,6 @@ exports[`Feature panel renders all flags 1`] = `
}
}
>
<Stack
horizontalAlign="space-between"
>
<StyledTextFieldBase
key="feature.notebookserverurl"
label="Notebook server URL"
onChange={[Function]}
placeholder="https://notebookserver"
styles={
{
"fieldGroup": {
"width": 300,
},
}
}
/>
<StyledTextFieldBase
key="feature.notebookservertoken"
label="Notebook server token"
onChange={[Function]}
placeholder=""
styles={
{
"fieldGroup": {
"width": 300,
},
}
}
/>
<StyledTextFieldBase
key="feature.notebookbasepath"
label="Notebook base path"
onChange={[Function]}
placeholder=""
styles={
{
"fieldGroup": {
"width": 300,
},
}
}
/>
</Stack>
<Stack
horizontalAlign="space-between"
>
@@ -286,6 +232,10 @@ exports[`Feature panel renders all flags 1`] = `
}
}
/>
</Stack>
<Stack
horizontalAlign="space-between"
>
<StyledTextFieldBase
key="feature.livyendpoint"
label="Livy endpoint"
+3 -3
View File
@@ -471,11 +471,11 @@ export default class Explorer {
}
}
public openNotebookTerminal(kind: ViewModels.TerminalKind): void {
this.connectToNotebookTerminal(kind);
public openTerminal(kind: ViewModels.TerminalKind): void {
this.connectToTerminal(kind);
}
private connectToNotebookTerminal(kind: ViewModels.TerminalKind): void {
private connectToTerminal(kind: ViewModels.TerminalKind): void {
let title: string;
switch (kind) {
@@ -143,7 +143,7 @@ export function createContextCommandBarButtons(
onCommandClick: () => {
const selectedCollection: ViewModels.Collection = selectedNodeState.findSelectedCollection();
if (userContext.features.enableCloudShell) {
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
container.openTerminal(ViewModels.TerminalKind.Mongo);
} else {
selectedCollection && selectedCollection.onNewMongoShellClick();
}
@@ -165,7 +165,7 @@ export function createContextCommandBarButtons(
iconSrc: HostedTerminalIcon,
iconAlt: label,
onCommandClick: () => {
container.openNotebookTerminal(ViewModels.TerminalKind.Cassandra);
container.openTerminal(ViewModels.TerminalKind.Cassandra);
},
commandButtonLabel: label,
ariaLabel: label,
@@ -531,7 +531,7 @@ function createOpenTerminalButtonByKind(
return;
}
if (userContext.features.enableCloudShell) {
container.openNotebookTerminal(terminalKind);
container.openTerminal(terminalKind);
}
},
commandButtonLabel: label,
@@ -35,14 +35,12 @@ const migrateOldData = () => {
componentName: AppStateComponentNames.MostRecentActivity,
globalAccountName: accountName,
},
itemsMap[accountId]
.filter((item) => (item.type as unknown as number) !== 1 && (item.type as string) !== "OpenNotebook")
.map((item) => {
if ((item.type as unknown as number) === 0) {
item.type = Type.OpenCollection;
}
return item;
}),
itemsMap[accountId].map((item) => {
if ((item.type as unknown as number) === 0) {
item.type = Type.OpenCollection;
}
return item;
}),
);
}
});
@@ -18,9 +18,9 @@ export const MongoQuickstartTutorial: React.FC = (): JSX.Element => {
return <></>;
}
let totalSteps = 9;
let totalSteps = 8;
if (userContext.isTryCosmosDBSubscription) {
totalSteps = 10;
totalSteps = 9;
}
switch (step) {
@@ -153,12 +153,12 @@ export const MongoQuickstartTutorial: React.FC = (): JSX.Element => {
case 7:
return (
<TeachingBubble
headline="Create notebook"
target={"#newNotebookBtn"}
headline="Launch full screen"
target={"#openFullScreenBtn"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(8),
onClick: () => (userContext.isTryCosmosDBSubscription ? setStep(8) : setStep(9)),
}}
secondaryButtonProps={{
text: "Previous",
@@ -166,32 +166,12 @@ export const MongoQuickstartTutorial: React.FC = (): JSX.Element => {
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent={"Step 7 of " + totalSteps}
>
Visualize your data, store queries in an interactive document
</TeachingBubble>
);
case 8:
return (
<TeachingBubble
headline="Launch full screen"
target={"#openFullScreenBtn"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => (userContext.isTryCosmosDBSubscription ? setStep(9) : setStep(10)),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(7),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent={"Step 8 of " + totalSteps}
>
This will open a new tab in your browser to use Cosmos DB Explorer. Using the provided URLs you can share
read-write or read-only access with other people.
</TeachingBubble>
);
case 9:
case 8:
return (
<TeachingBubble
headline="Boost your experience"
@@ -199,24 +179,24 @@ export const MongoQuickstartTutorial: React.FC = (): JSX.Element => {
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(10),
onClick: () => setStep(9),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(8),
onClick: () => setStep(7),
}}
calloutProps={{ directionalHint: DirectionalHint.leftCenter }}
onDismiss={() => onDimissTeachingBubble()}
footerContent={"Step 9 of " + totalSteps}
footerContent={"Step 8 of " + totalSteps}
>
Unlock everything Azure Cosmos DB has to offer When you&apos;re ready, upgrade to production.
</TeachingBubble>
);
case 10:
case 9:
return (
<TeachingBubble
headline="Congratulations!"
target={"#newNotebookBtn"}
target={"#openFullScreenBtn"}
hasCloseButton
primaryButtonProps={{
text: "Launch connect",
@@ -227,7 +207,7 @@ export const MongoQuickstartTutorial: React.FC = (): JSX.Element => {
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => (userContext.isTryCosmosDBSubscription ? setStep(9) : setStep(8)),
onClick: () => (userContext.isTryCosmosDBSubscription ? setStep(8) : setStep(7)),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent={"Step " + totalSteps + " of " + totalSteps}
@@ -0,0 +1,52 @@
import { fireEvent, render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import { useTeachingBubble } from "hooks/useTeachingBubble";
import React from "react";
import { updateUserContext } from "UserContext";
import { MongoQuickstartTutorial } from "./MongoQuickstartTutorial";
import { SQLQuickstartTutorial } from "./SQLQuickstartTutorial";
describe("quickstart tutorials", () => {
beforeEach(() => {
const target = document.createElement("div");
target.id = "openFullScreenBtn";
document.body.appendChild(target);
useTeachingBubble.setState({ step: 1 });
});
afterEach(() => {
document.body.innerHTML = "";
});
it("continues the SQL tour from full screen to the final step", () => {
updateUserContext({ apiType: "SQL", isTryCosmosDBSubscription: false });
useTeachingBubble.setState({ step: 6 });
const { rerender } = render(<SQLQuickstartTutorial />);
expect(screen.getByText("Launch full screen")).toBeInTheDocument();
expect(screen.getByText("Step 6 of 7")).toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: "Next" }));
rerender(<SQLQuickstartTutorial />);
expect(screen.getByText("Congratulations!")).toBeInTheDocument();
expect(screen.getByText("Step 7 of 7")).toBeInTheDocument();
});
it("continues the Mongo tour from full screen to the final step", () => {
updateUserContext({ apiType: "Mongo", isTryCosmosDBSubscription: false });
useTeachingBubble.setState({ step: 7 });
const { rerender } = render(<MongoQuickstartTutorial />);
expect(screen.getByText("Launch full screen")).toBeInTheDocument();
expect(screen.getByText("Step 7 of 8")).toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: "Next" }));
rerender(<MongoQuickstartTutorial />);
expect(screen.getByText("Congratulations!")).toBeInTheDocument();
expect(screen.getByText("Step 8 of 8")).toBeInTheDocument();
});
});
@@ -17,9 +17,9 @@ export const SQLQuickstartTutorial: React.FC = (): JSX.Element => {
if (userContext.apiType !== "SQL") {
return <></>;
}
let totalSteps = 8;
let totalSteps = 7;
if (userContext.isTryCosmosDBSubscription) {
totalSteps = 9;
totalSteps = 8;
}
switch (step) {
@@ -130,12 +130,12 @@ export const SQLQuickstartTutorial: React.FC = (): JSX.Element => {
case 6:
return (
<TeachingBubble
headline="Create notebook"
target={"#newNotebookBtn"}
headline="Launch full screen"
target={"#openFullScreenBtn"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(7),
onClick: () => (userContext.isTryCosmosDBSubscription ? setStep(7) : setStep(8)),
}}
secondaryButtonProps={{
text: "Previous",
@@ -143,32 +143,12 @@ export const SQLQuickstartTutorial: React.FC = (): JSX.Element => {
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent={"Step 6 of " + totalSteps}
>
Visualize your data, store queries in an interactive document
</TeachingBubble>
);
case 7:
return (
<TeachingBubble
headline="Launch full screen"
target={"#openFullScreenBtn"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => (userContext.isTryCosmosDBSubscription ? setStep(8) : setStep(9)),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(6),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent={"Step 7 of " + totalSteps}
>
This will open a new tab in your browser to use Cosmos DB Explorer. Using the provided URLs you can share
read-write or read-only access with other people.
</TeachingBubble>
);
case 8:
case 7:
return (
<TeachingBubble
headline="Boost your experience"
@@ -176,24 +156,24 @@ export const SQLQuickstartTutorial: React.FC = (): JSX.Element => {
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(9),
onClick: () => setStep(8),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(7),
onClick: () => setStep(6),
}}
calloutProps={{ directionalHint: DirectionalHint.leftCenter }}
onDismiss={() => onDimissTeachingBubble()}
footerContent={"Step 8 of " + totalSteps}
footerContent={"Step 7 of " + totalSteps}
>
Unlock everything Azure Cosmos DB has to offer When you&apos;re ready, upgrade to production.
</TeachingBubble>
);
case 9:
case 8:
return (
<TeachingBubble
headline="Congratulations!"
target={"#newNotebookBtn"}
target={"#openFullScreenBtn"}
hasCloseButton
primaryButtonProps={{
text: "Launch connect",
@@ -204,7 +184,7 @@ export const SQLQuickstartTutorial: React.FC = (): JSX.Element => {
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => (userContext.isTryCosmosDBSubscription ? setStep(8) : setStep(7)),
onClick: () => (userContext.isTryCosmosDBSubscription ? setStep(7) : setStep(6)),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent={"Step " + totalSteps + " of " + totalSteps}
+3 -3
View File
@@ -407,7 +407,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
iconSrc: PowerShellIcon,
title: t(Keys.splashScreen.shell.postgres.title),
description: t(Keys.splashScreen.shell.postgres.description),
onClick: () => container.openNotebookTerminal(TerminalKind.Postgres),
onClick: () => container.openTerminal(TerminalKind.Postgres),
};
}
@@ -426,7 +426,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
linkUrl: VCoreMongoNativeAuthLearnMoreUrl,
});
} else {
container.openNotebookTerminal(TerminalKind.VCoreMongo);
container.openTerminal(TerminalKind.VCoreMongo);
}
},
};
@@ -620,7 +620,7 @@ export const SplashScreen: React.FC<SplashScreenProps> = ({ explorer }) => {
};
const getRecentItems = (): JSX.Element => {
const recentItems = createRecentItems()?.filter((item) => item.description !== "Notebook");
const recentItems = createRecentItems() ?? [];
return (
<Stack>
+4 -4
View File
@@ -17,9 +17,9 @@ export interface TerminalTabOptions extends ViewModels.TabOptions {
}
export default class TerminalTab extends TabsBase {
public readonly html = '<div style="height: 100%" data-bind="react:notebookTerminalComponentAdapter"></div> ';
public readonly html = '<div style="height: 100%" data-bind="react:cloudShellTerminalComponentAdapter"></div> ';
private container: Explorer;
private notebookTerminalComponentAdapter: ReactAdapter;
private cloudShellTerminalComponentAdapter: ReactAdapter;
private isAllPublicIPAddressesEnabled: ko.Observable<boolean>;
constructor(options: TerminalTabOptions) {
@@ -27,7 +27,7 @@ export default class TerminalTab extends TabsBase {
this.container = options.container;
this.isAllPublicIPAddressesEnabled = ko.observable(true);
this.notebookTerminalComponentAdapter = new CloudShellTerminalComponentAdapter(
this.cloudShellTerminalComponentAdapter = new CloudShellTerminalComponentAdapter(
() => userContext?.databaseAccount,
() => this.tabId,
() => this.getUsername(),
@@ -35,7 +35,7 @@ export default class TerminalTab extends TabsBase {
options.kind,
);
this.notebookTerminalComponentAdapter.parameters = ko.computed<boolean>(() => {
this.cloudShellTerminalComponentAdapter.parameters = ko.computed<boolean>(() => {
return this.isTemplateReady() && this.isAllPublicIPAddressesEnabled();
});
-4
View File
@@ -75,8 +75,6 @@ export default class Collection implements ViewModels.Collection {
public throughput: ko.Computed<number>;
public rawDataModel: DataModels.Collection;
public analyticalStorageTtl: ko.Observable<number>;
public schema: DataModels.ISchema;
public requestSchema: () => void;
public geospatialConfig: ko.Observable<DataModels.GeospatialConfig>;
// TODO move this to API customization class
@@ -129,8 +127,6 @@ export default class Collection implements ViewModels.Collection {
this.conflictResolutionPolicy = ko.observable(data.conflictResolutionPolicy);
this.changeFeedPolicy = ko.observable<DataModels.ChangeFeedPolicy>(data.changeFeedPolicy);
this.analyticalStorageTtl = ko.observable(data.analyticalStorageTtl);
this.schema = data.schema;
this.requestSchema = data.requestSchema;
this.geospatialConfig = ko.observable(data.geospatialConfig);
this.computedProperties = ko.observable(data.computedProperties);
this.materializedViews = ko.observable(data.materializedViews);
-86
View File
@@ -1,86 +0,0 @@
import { HttpStatusCodes } from "../../Common/Constants";
import * as DataModels from "../../Contracts/DataModels";
import { JunoClient } from "../../Juno/JunoClient";
import { Features } from "../../Platform/Hosted/extractFeatures";
import { updateUserContext, userContext } from "../../UserContext";
import Explorer from "../Explorer";
import Database from "./Database";
const createMockContainer = (): Explorer => {
const mockContainer = new Explorer();
return mockContainer;
};
updateUserContext({
subscriptionId: "fakeSubscriptionId",
resourceGroup: "fakeResourceGroup",
databaseAccount: {
id: "id",
name: "fakeName",
location: "fakeLocation",
type: "fakeType",
kind: "fakeKind",
properties: {
documentEndpoint: "fakeEndpoint",
tableEndpoint: "fakeEndpoint",
gremlinEndpoint: "fakeEndpoint",
cassandraEndpoint: "fakeEndpoint",
},
},
});
describe("Add Schema", () => {
it("should not call requestSchema or getSchema if analyticalStorageTtl is undefined", () => {
const collection: DataModels.Collection = { id: "fakeId" } as DataModels.Collection;
collection.analyticalStorageTtl = undefined;
const database = new Database(createMockContainer(), collection);
database.container = createMockContainer();
database.junoClient = new JunoClient();
database.junoClient.requestSchema = jest.fn();
database.junoClient.getSchema = jest.fn();
database.addSchema(collection);
expect(database.junoClient.requestSchema).toHaveBeenCalledTimes(0);
});
it("should call requestSchema or getSchema if analyticalStorageTtl is not undefined", () => {
const collection: DataModels.Collection = {} as DataModels.Collection;
collection.analyticalStorageTtl = 0;
const database = new Database(createMockContainer(), collection);
database.container = createMockContainer();
updateUserContext({
features: {
enableSchema: true,
} as Features,
});
database.junoClient = new JunoClient();
database.junoClient.requestSchema = jest.fn();
database.junoClient.getSchema = jest.fn().mockResolvedValue({ status: HttpStatusCodes.OK, data: {} });
jest.useFakeTimers();
const interval = 5000;
const checkForSchema: NodeJS.Timeout = database.addSchema(collection, interval);
jest.advanceTimersByTime(interval + 1000);
expect(database.junoClient.requestSchema).toHaveBeenCalledWith({
id: undefined,
subscriptionId: userContext.subscriptionId,
resourceGroup: userContext.resourceGroup,
accountName: userContext.databaseAccount.name,
resource: `dbs/${database.id()}/colls/${collection.id}`,
status: "new",
});
expect(checkForSchema).not.toBeNull();
expect(database.junoClient.getSchema).toHaveBeenCalledWith(
userContext.subscriptionId,
userContext.resourceGroup,
userContext.databaseAccount.name,
database.id(),
collection.id,
);
});
});
-47
View File
@@ -8,7 +8,6 @@ import { readCollections, readCollectionsWithPagination } from "../../Common/dat
import { readDatabaseOffer } from "../../Common/dataAccess/readDatabaseOffer";
import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { IJunoResponse, JunoClient } from "../../Juno/JunoClient";
import * as StorageUtility from "../../Shared/StorageUtility";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
@@ -35,7 +34,6 @@ export default class Database implements ViewModels.Database {
public isDatabaseExpanded: ko.Observable<boolean>;
public isDatabaseShared: ko.Computed<boolean>;
public selectedSubnodeKind: ko.Observable<ViewModels.CollectionTabKind>;
public junoClient: JunoClient;
public isSampleDB: boolean;
public collectionsContinuationToken?: string;
private isOfferRead: boolean;
@@ -55,7 +53,6 @@ export default class Database implements ViewModels.Database {
this.isDatabaseShared = ko.pureComputed(() => {
return this.offer && !!this.offer();
});
this.junoClient = new JunoClient();
this.isSampleDB = false;
this.isOfferRead = false;
}
@@ -205,10 +202,6 @@ export default class Database implements ViewModels.Database {
}
const deltaCollections = this.getDeltaCollections(collections);
collections.forEach((collection: DataModels.Collection) => {
this.addSchema(collection);
});
deltaCollections.toAdd.forEach((collection: DataModels.Collection) => {
const collectionVM: Collection = new Collection(this.container, this.id(), collection);
collectionVMs.push(collectionVM);
@@ -314,44 +307,4 @@ export default class Database implements ViewModels.Database {
this.collections(collectionsToKeep);
}
public addSchema(collection: DataModels.Collection, interval?: number): NodeJS.Timeout {
let checkForSchema: NodeJS.Timeout;
interval = interval || 5000;
if (collection.analyticalStorageTtl !== undefined && userContext.features.enableSchema) {
collection.requestSchema = () => {
this.junoClient.requestSchema({
id: undefined,
subscriptionId: userContext.subscriptionId,
resourceGroup: userContext.resourceGroup,
accountName: userContext.databaseAccount.name,
resource: `dbs/${this.id()}/colls/${collection.id}`,
status: "new",
});
checkForSchema = setInterval(async () => {
const response: IJunoResponse<DataModels.ISchema> = await this.junoClient.getSchema(
userContext.subscriptionId,
userContext.resourceGroup,
userContext.databaseAccount.name,
this.id(),
collection.id,
);
if (response.status >= 404) {
clearInterval(checkForSchema);
}
if (response.data !== undefined) {
clearInterval(checkForSchema);
collection.schema = response.data;
}
}, interval);
};
collection.requestSchema();
}
return checkForSchema;
}
}
@@ -1,240 +0,0 @@
import { shallow } from "enzyme";
import React from "react";
import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import {
LegacyTreeComponent,
LegacyTreeComponentProps,
LegacyTreeNode,
} from "../Controls/TreeComponent/LegacyTreeComponent";
import Explorer from "../Explorer";
import Collection from "./Collection";
import { ResourceTreeAdapter } from "./ResourceTreeAdapter";
const schema: DataModels.ISchema = {
id: "fakeSchemaId",
accountName: "fakeAccountName",
resource: "dbs/FakeDbName/colls/FakeCollectionName",
fields: [
{
dataType: {
code: 15,
name: "String",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "_rid",
path: "_rid",
maxRepetitionLevel: 0,
maxDefinitionLevel: 1,
},
{
dataType: {
code: 11,
name: "Int64",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "_ts",
path: "_ts",
maxRepetitionLevel: 0,
maxDefinitionLevel: 1,
},
{
dataType: {
code: 15,
name: "String",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "id",
path: "id",
maxRepetitionLevel: 0,
maxDefinitionLevel: 1,
},
{
dataType: {
code: 15,
name: "String",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "pk",
path: "pk",
maxRepetitionLevel: 0,
maxDefinitionLevel: 1,
},
{
dataType: {
code: 15,
name: "String",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "other",
path: "other",
maxRepetitionLevel: 0,
maxDefinitionLevel: 1,
},
{
dataType: {
code: 15,
name: "String",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "name",
path: "nested.name",
maxRepetitionLevel: 0,
maxDefinitionLevel: 1,
},
{
dataType: {
code: 11,
name: "Int64",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "someNumber",
path: "nested.someNumber",
maxRepetitionLevel: 0,
maxDefinitionLevel: 1,
},
{
dataType: {
code: 17,
name: "Double",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "anotherNumber",
path: "nested.anotherNumber",
maxRepetitionLevel: 0,
maxDefinitionLevel: 1,
},
{
dataType: {
code: 15,
name: "String",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "name",
path: "items.list.items.name",
maxRepetitionLevel: 1,
maxDefinitionLevel: 3,
},
{
dataType: {
code: 11,
name: "Int64",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "someNumber",
path: "items.list.items.someNumber",
maxRepetitionLevel: 1,
maxDefinitionLevel: 3,
},
{
dataType: {
code: 17,
name: "Double",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "anotherNumber",
path: "items.list.items.anotherNumber",
maxRepetitionLevel: 1,
maxDefinitionLevel: 3,
},
{
dataType: {
code: 15,
name: "String",
},
hasNulls: true,
isArray: false,
schemaType: {
code: 0,
name: "Data",
},
name: "_etag",
path: "_etag",
maxRepetitionLevel: 0,
maxDefinitionLevel: 1,
},
],
};
const createMockCollection = (): ViewModels.Collection => {
const mockCollection = {} as DataModels.Collection;
mockCollection._rid = "fakeRid";
mockCollection._self = "fakeSelf";
mockCollection.id = "fakeId";
mockCollection.analyticalStorageTtl = 0;
mockCollection.schema = schema;
const mockCollectionVM: ViewModels.Collection = new Collection(new Explorer(), "fakeDatabaseId", mockCollection);
return mockCollectionVM;
};
describe("Resource tree for schema", () => {
const mockContainer = new Explorer();
const resourceTree = new ResourceTreeAdapter(mockContainer);
it("should render", () => {
const rootNode: LegacyTreeNode = resourceTree.buildSchemaNode(createMockCollection());
const props: LegacyTreeComponentProps = {
rootNode,
className: "dataResourceTree",
};
const wrapper = shallow(<LegacyTreeComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
});
-73
View File
@@ -6,7 +6,6 @@ import * as React from "react";
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
import CollectionIcon from "../../../images/tree-collection.svg";
import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { userContext } from "../../UserContext";
import { isServerlessAccount } from "../../Utils/CapabilityUtils";
@@ -138,11 +137,6 @@ export class ResourceTreeAdapter implements ReactAdapter {
});
}
const schemaNode: LegacyTreeNode = this.buildSchemaNode(collection);
if (schemaNode) {
children.push(schemaNode);
}
if (shouldShowScriptNodes()) {
children.push(this.buildStoredProcedureNode(collection));
children.push(this.buildUserDefinedFunctionsNode(collection));
@@ -275,73 +269,6 @@ export class ResourceTreeAdapter implements ReactAdapter {
};
}
public buildSchemaNode(collection: ViewModels.Collection): LegacyTreeNode {
if (collection.analyticalStorageTtl() == undefined) {
return undefined;
}
if (!collection.schema || !collection.schema.fields) {
return undefined;
}
return {
label: "Schema",
children: this.getSchemaNodes(collection.schema.fields),
onClick: () => {
collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Schema);
useTabs.getState().refreshActiveTab((tab: TabsBase) => tab.collection && tab.collection.rid === collection.rid);
},
};
}
private getSchemaNodes(fields: DataModels.IDataField[]): LegacyTreeNode[] {
const schema: any = {};
//unflatten
fields.forEach((field: DataModels.IDataField, fieldIndex: number) => {
const path: string[] = field.path.split(".");
const fieldProperties = [field.dataType.name, `HasNulls: ${field.hasNulls}`];
let current: any = {};
path.forEach((name: string, pathIndex: number) => {
if (pathIndex === 0) {
if (schema[name] === undefined) {
if (pathIndex === path.length - 1) {
schema[name] = fieldProperties;
} else {
schema[name] = {};
}
}
current = schema[name];
} else {
if (current[name] === undefined) {
if (pathIndex === path.length - 1) {
current[name] = fieldProperties;
} else {
current[name] = {};
}
}
current = current[name];
}
});
});
const traverse = (obj: any): LegacyTreeNode[] => {
const children: LegacyTreeNode[] = [];
if (obj !== null && !Array.isArray(obj) && typeof obj === "object") {
Object.entries(obj).forEach(([key, value]) => {
children.push({ label: key, children: traverse(value) });
});
} else if (Array.isArray(obj)) {
return [{ label: obj[0] }, { label: obj[1] }];
}
return children;
};
return traverse(schema);
}
public triggerRender() {
window.requestAnimationFrame(() => this.parameters(Date.now()));
}
@@ -1,173 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Resource tree for schema should render 1`] = `
<div
className="treeComponent dataResourceTree"
role="tree"
>
<LegacyTreeNodeComponent
generation={0}
node={
{
"children": [
{
"children": [
{
"label": "String",
},
{
"label": "HasNulls: true",
},
],
"label": "_rid",
},
{
"children": [
{
"label": "Int64",
},
{
"label": "HasNulls: true",
},
],
"label": "_ts",
},
{
"children": [
{
"label": "String",
},
{
"label": "HasNulls: true",
},
],
"label": "id",
},
{
"children": [
{
"label": "String",
},
{
"label": "HasNulls: true",
},
],
"label": "pk",
},
{
"children": [
{
"label": "String",
},
{
"label": "HasNulls: true",
},
],
"label": "other",
},
{
"children": [
{
"children": [
{
"label": "String",
},
{
"label": "HasNulls: true",
},
],
"label": "name",
},
{
"children": [
{
"label": "Int64",
},
{
"label": "HasNulls: true",
},
],
"label": "someNumber",
},
{
"children": [
{
"label": "Double",
},
{
"label": "HasNulls: true",
},
],
"label": "anotherNumber",
},
],
"label": "nested",
},
{
"children": [
{
"children": [
{
"children": [
{
"children": [
{
"label": "String",
},
{
"label": "HasNulls: true",
},
],
"label": "name",
},
{
"children": [
{
"label": "Int64",
},
{
"label": "HasNulls: true",
},
],
"label": "someNumber",
},
{
"children": [
{
"label": "Double",
},
{
"label": "HasNulls: true",
},
],
"label": "anotherNumber",
},
],
"label": "items",
},
],
"label": "list",
},
],
"label": "items",
},
{
"children": [
{
"label": "String",
},
{
"label": "HasNulls: true",
},
],
"label": "_etag",
},
],
"label": "Schema",
"onClick": [Function],
}
}
paddingLeft={0}
/>
</div>
`;
@@ -25,61 +25,6 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the Ca
"label": "Rows",
"onClick": [Function],
},
{
"children": [
{
"children": [
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "street",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: true",
},
],
"label": "line2",
},
{
"children": [
{
"label": "number",
},
{
"label": "HasNulls: false",
},
],
"label": "zip",
},
],
"label": "address",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "orderId",
},
],
"label": "Schema",
"onClick": [Function],
},
],
"className": "collectionNode",
"contextMenu": [
@@ -399,61 +344,6 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the Mo
"label": "Scale & Settings",
"onClick": [Function],
},
{
"children": [
{
"children": [
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "street",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: true",
},
],
"label": "line2",
},
{
"children": [
{
"label": "number",
},
{
"label": "HasNulls: false",
},
],
"label": "zip",
},
],
"label": "address",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "orderId",
},
],
"label": "Schema",
"onClick": [Function],
},
],
"className": "collectionNode",
"contextMenu": [
@@ -821,61 +711,6 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the SQ
"label": "Settings",
"onClick": [Function],
},
{
"children": [
{
"children": [
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "street",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: true",
},
],
"label": "line2",
},
{
"children": [
{
"label": "number",
},
{
"label": "HasNulls: false",
},
],
"label": "zip",
},
],
"label": "address",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "orderId",
},
],
"label": "Schema",
"onClick": [Function],
},
],
"className": "collectionNode",
"contextMenu": [
@@ -1335,61 +1170,6 @@ exports[`createDatabaseTreeNodes generates the correct tree structure for the SQ
"label": "Scale & Settings",
"onClick": [Function],
},
{
"children": [
{
"children": [
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "street",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: true",
},
],
"label": "line2",
},
{
"children": [
{
"label": "number",
},
{
"label": "HasNulls: false",
},
],
"label": "zip",
},
],
"label": "address",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "orderId",
},
],
"label": "Schema",
"onClick": [Function],
},
{
"children": [],
"label": "Stored Procedures",
@@ -1941,61 +1721,6 @@ exports[`createDatabaseTreeNodes using NoSQL API on Hosted Platform creates expe
"label": "Scale & Settings",
"onClick": [Function],
},
{
"children": [
{
"children": [
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "street",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: true",
},
],
"label": "line2",
},
{
"children": [
{
"label": "number",
},
{
"label": "HasNulls: false",
},
],
"label": "zip",
},
],
"label": "address",
},
{
"children": [
{
"label": "string",
},
{
"label": "HasNulls: false",
},
],
"label": "orderId",
},
],
"label": "Schema",
"onClick": [Function],
},
{
"children": [],
"label": "Stored Procedures",
-26
View File
@@ -153,7 +153,6 @@ const baseCollection = {
onDocumentDBDocumentsClick: jest.fn(),
onNewQueryClick: jest.fn(),
onConflictsClick: jest.fn(),
onSchemaAnalyzerClick: jest.fn(),
} as unknown as ViewModels.Collection;
/** A basic test database that can be expanded on in tests */
@@ -297,31 +296,6 @@ describe("createDatabaseTreeNodes", () => {
id: ko.observable("schemaCollection"),
container: explorer,
databaseId: sharedDb.id(),
analyticalStorageTtl: ko.observable<number>(5),
schema: {
fields: [
{
path: "address.street",
dataType: { name: "string" },
hasNulls: false,
},
{
path: "address.line2",
dataType: { name: "string" },
hasNulls: true,
},
{
path: "address.zip",
dataType: { name: "number" },
hasNulls: false,
},
{
path: "orderId",
dataType: { name: "string" },
hasNulls: false,
},
],
} as unknown,
} as ViewModels.Collection;
conflictsCollection = {
-80
View File
@@ -18,7 +18,6 @@ import { isServerlessAccount } from "Utils/CapabilityUtils";
import { useTabs } from "hooks/useTabs";
import React from "react";
import { Platform, configContext } from "../../ConfigContext";
import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels";
import { userContext } from "../../UserContext";
import * as ResourceTreeContextMenuButtonFactory from "../ContextMenuButtonFactory";
@@ -347,11 +346,6 @@ const buildCollectionNodeChildren = (
});
}
const schemaNode: TreeNode = buildSchemaNode(collection, container, refreshActiveTab);
if (schemaNode) {
children.push(schemaNode);
}
const onUpdateDatabase = () => useDatabases.getState().updateDatabase(database);
if (shouldShowScriptNodes()) {
@@ -468,77 +462,3 @@ const buildTriggerNode = (
},
};
};
const buildSchemaNode = (
collection: ViewModels.Collection,
container: Explorer,
refreshActiveTab: (comparator: (tab: TabsBase) => boolean) => void,
): TreeNode => {
if (collection.analyticalStorageTtl() === undefined) {
return undefined;
}
if (!collection.schema || !collection.schema.fields) {
return undefined;
}
return {
label: "Schema",
children: getSchemaNodes(collection.schema.fields),
onClick: () => {
collection.selectedSubnodeKind(ViewModels.CollectionTabKind.Schema);
refreshActiveTab((tab: TabsBase) => tab.collection && tab.collection.rid === collection.rid);
},
};
};
const getSchemaNodes = (fields: DataModels.IDataField[]): TreeNode[] => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const schema: any = {};
//unflatten
fields.forEach((field: DataModels.IDataField) => {
const path: string[] = field.path.split(".");
const fieldProperties = [field.dataType.name, `HasNulls: ${field.hasNulls}`];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let current: any = {};
path.forEach((name: string, pathIndex: number) => {
if (pathIndex === 0) {
if (schema[name] === undefined) {
if (pathIndex === path.length - 1) {
schema[name] = fieldProperties;
} else {
schema[name] = {};
}
}
current = schema[name];
} else {
if (current[name] === undefined) {
if (pathIndex === path.length - 1) {
current[name] = fieldProperties;
} else {
current[name] = {};
}
}
current = current[name];
}
});
});
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const traverse = (obj: any): TreeNode[] => {
const children: TreeNode[] = [];
if (obj !== undefined && !Array.isArray(obj) && typeof obj === "object") {
Object.entries(obj).forEach(([key, value]) => {
children.push({ label: key, children: traverse(value) });
});
} else if (Array.isArray(obj)) {
return [{ label: obj[0] }, { label: obj[1] }];
}
return children;
};
return traverse(schema);
};
-136
View File
@@ -1,136 +0,0 @@
import { allowedJunoOrigins, validateEndpoint } from "Utils/EndpointUtils";
import { HttpHeaders, HttpStatusCodes } from "../Common/Constants";
import { configContext } from "../ConfigContext";
import * as DataModels from "../Contracts/DataModels";
import { userContext } from "../UserContext";
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
export interface IJunoResponse<T> {
status: number;
data: T;
}
export interface IGalleryItem {
id: string;
name: string;
description: string;
gitSha: string;
tags: string[];
author: string;
thumbnailUrl: string;
created: string;
isSample: boolean;
downloads: number;
favorites: number;
views: number;
newCellId: string;
policyViolations: string[];
pendingScanJobIds: string[];
}
export class JunoClient {
public async increaseNotebookViews(id: string): Promise<IJunoResponse<IGalleryItem>> {
const response = await window.fetch(`${this.getNotebooksUrl()}/gallery/${id}/views`, {
method: "PATCH",
});
let data: IGalleryItem;
if (response.status === HttpStatusCodes.OK) {
data = await response.json();
}
return {
status: response.status,
data,
};
}
public async requestSchema(
schemaRequest: DataModels.ISchemaRequest,
): Promise<IJunoResponse<DataModels.ISchemaRequest>> {
const response = await window.fetch(`${this.getAnalyticsUrl()}/schema/request`, {
method: "POST",
body: JSON.stringify(schemaRequest),
headers: JunoClient.getHeaders(),
});
let data: DataModels.ISchemaRequest;
if (response.status === HttpStatusCodes.OK) {
data = await response.json();
}
return {
status: response.status,
data,
};
}
public async getSchema(
subscriptionId: string,
resourceGroup: string,
accountName: string,
databaseName: string,
containerName: string,
): Promise<IJunoResponse<DataModels.ISchema>> {
const response = await window.fetch(
`${this.getAnalyticsUrl()}/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/databaseAccounts/${accountName}/schema/${databaseName}/${containerName}`,
{
method: "GET",
headers: JunoClient.getHeaders(),
},
);
let data: DataModels.ISchema;
if (response.status === HttpStatusCodes.OK) {
data = await response.json();
}
return {
status: response.status,
data,
};
}
private async getNotebooks(input: RequestInfo, init?: RequestInit): Promise<IJunoResponse<IGalleryItem[]>> {
const response = await window.fetch(input, init);
let data: IGalleryItem[];
if (response.status === HttpStatusCodes.OK) {
data = await response.json();
}
return {
status: response.status,
data,
};
}
// public for tests
public static getJunoEndpoint(): string {
const junoEndpoint = userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
if (!validateEndpoint(junoEndpoint, allowedJunoOrigins)) {
const error = `${junoEndpoint} not allowed as juno endpoint`;
console.error(error);
throw new Error(error);
}
return junoEndpoint;
}
private getNotebooksUrl(): string {
return `${JunoClient.getJunoEndpoint()}/api/notebooks`;
}
private getAnalyticsUrl(): string {
return `${JunoClient.getJunoEndpoint()}/api/analytics`;
}
private static getHeaders(): HeadersInit {
const authorizationHeader = getAuthorizationHeader();
return {
[authorizationHeader.header]: authorizationHeader.token,
[HttpHeaders.contentType]: "application/json",
};
}
}
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Studijní materiály",
"nextSteps": "Další kroky",
"tipsAndLearnMore": "Tipy a další informace",
"notebook": "Poznámkový blok",
"needHelp": "Potřebujete pomoc?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "Vytvořeno: {{numSucceeded}}, omezeno: {{numThrottled}}, počet chyb: {{numFailed}}",
"uploadedFiles": "Nahrané soubory"
},
"copyNotebook": {
"copyFailedError": "Nepovedlo se zkopírovat {{name}} do {{destination}}",
"uploadFailedError": "Nepodařilo se nahrát {{name}}",
"location": "Umístění",
"locationAriaLabel": "Umístění",
"selectLocation": "Vyberte umístění poznámkového bloku ke kopírování.",
"name": "Název"
},
"publishNotebook": {
"publishFailedError": "Publikování do galerie se {{notebookName}} nezdařilo.",
"publishDescription": "Po publikování se tento poznámkový blok zobrazí ve veřejné galerii poznámkových bloků Azure Cosmos DB. Před publikováním se ujistěte, že jste odebrali všechna citlivá data nebo výstup.",
"publishPrompt": "Chcete {{name}} publikovat a nasdílet do galerie?",
"coverImage": "Titulní obrázek",
"coverImageUrl": "Adresa URL titulního obrázku",
"name": "Název",
"description": "Popis",
"tags": "Značky",
"tagsPlaceholder": "Volitelná značka 1, volitelná značka 2",
"preview": "Náhled",
"urlType": "Adresa URL",
"customImage": "Vlastní image",
"takeScreenshot": "Pořídit snímek obrazovky",
"useFirstDisplayOutput": "Použít první zobrazený výstup",
"failedToCaptureOutput": "Nepovedlo se zachytit první výstup.",
"outputDoesNotExist": "Pro žádnou z buněk neexistuje výstup.",
"failedToConvertError": "Nepovedlo se převést {{fileName}} do formátu base64",
"failedToUploadError": "Nepodařilo se nahrát {{fileName}}."
},
"changePartitionKey": {
"failedToStartError": "Nepovedlo se spustit úlohu přenosu dat.",
"suboptimalPartitionKeyError": "Upozornění: Systém zjistil, že vaše kolekce pravděpodobně používá neoptimální klíč oddílu.",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Lernressourcen",
"nextSteps": "Nächste Schritte",
"tipsAndLearnMore": "Tipps und weitere Informationen",
"notebook": "Notebook",
"needHelp": "Benötigen Sie Hilfe?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} erstellt, {{numThrottled}} gedrosselt, {{numFailed}} Fehler",
"uploadedFiles": "Hochgeladene Dateien"
},
"copyNotebook": {
"copyFailedError": "Fehler beim Kopieren von {{name}} nach {{destination}}",
"uploadFailedError": "Fehler beim Hochladen von „{{name}}“",
"location": "Speicherort",
"locationAriaLabel": "Speicherort",
"selectLocation": "Notizbuchspeicherort zum Kopieren auswählen",
"name": "Name"
},
"publishNotebook": {
"publishFailedError": "Fehler beim Veröffentlichen von {{notebookName}} im Katalog",
"publishDescription": "Nach der Veröffentlichung wird dieses Notebook im öffentlichen Katalog Azure Cosmos DB Notebooks angezeigt. Stellen Sie sicher, dass Sie alle vertraulichen Daten oder Ausgaben vor der Veröffentlichung entfernt haben.",
"publishPrompt": "Möchten Sie „{{name}}“ im Katalog veröffentlichen und freigeben?",
"coverImage": "Titelbild",
"coverImageUrl": "Titelbild-URL",
"name": "Name",
"description": "Beschreibung",
"tags": "Kategorien",
"tagsPlaceholder": "Optionales Tag 1, optionales Tag 2",
"preview": "Vorschau",
"urlType": "URL",
"customImage": "Benutzerdefiniertes Image",
"takeScreenshot": "Screenshot erstellen",
"useFirstDisplayOutput": "Erste Anzeigeausgabe verwenden",
"failedToCaptureOutput": "Fehler beim Erfassen der ersten Ausgabe",
"outputDoesNotExist": "Für keine der Zellen ist eine Ausgabe vorhanden.",
"failedToConvertError": "Fehler beim Konvertieren von {{fileName}} in das Base64-Format",
"failedToUploadError": "Fehler beim Hochladen von „{{fileName}}“"
},
"changePartitionKey": {
"failedToStartError": "Fehler beim Starten des Datenübertragungsauftrags",
"suboptimalPartitionKeyError": "Warnung: Das System hat festgestellt, dass Ihre Sammlung möglicherweise keinen optimalen Partitionsschlüssel verwendet.",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Learning Resources",
"nextSteps": "Next steps",
"tipsAndLearnMore": "Tips & learn more",
"notebook": "Notebook",
"needHelp": "Need help?"
},
"top3Items": {
@@ -668,34 +667,6 @@
"uploadStatus": "{{numSucceeded}} created, {{numThrottled}} throttled, {{numFailed}} errors",
"uploadedFiles": "Uploaded files"
},
"copyNotebook": {
"copyFailedError": "Failed to copy {{name}} to {{destination}}",
"uploadFailedError": "Failed to upload {{name}}",
"location": "Location",
"locationAriaLabel": "Location",
"selectLocation": "Select a notebook location to copy",
"name": "Name"
},
"publishNotebook": {
"publishFailedError": "Failed to publish {{notebookName}} to gallery",
"publishDescription": "When published, this notebook will appear in the Azure Cosmos DB notebooks public gallery. Make sure you have removed any sensitive data or output before publishing.",
"publishPrompt": "Would you like to publish and share \"{{name}}\" to the gallery?",
"coverImage": "Cover image",
"coverImageUrl": "Cover image url",
"name": "Name",
"description": "Description",
"tags": "Tags",
"tagsPlaceholder": "Optional tag 1, Optional tag 2",
"preview": "Preview",
"urlType": "URL",
"customImage": "Custom Image",
"takeScreenshot": "Take Screenshot",
"useFirstDisplayOutput": "Use First Display Output",
"failedToCaptureOutput": "Failed to capture first output",
"outputDoesNotExist": "Output does not exist for any of the cells.",
"failedToConvertError": "Failed to convert {{fileName}} to base64 format",
"failedToUploadError": "Failed to upload {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "Failed to start data transfer job",
"suboptimalPartitionKeyError": "Warning: The system has detected that your collection may be using a suboptimal partition key",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Recursos de aprendizaje",
"nextSteps": "Siguientes pasos",
"tipsAndLearnMore": "Sugerencias y más información",
"notebook": "Notebook",
"needHelp": "¿Necesita ayuda?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} creado, {{numThrottled}} limitado, {{numFailed}} errores",
"uploadedFiles": "Archivos cargados"
},
"copyNotebook": {
"copyFailedError": "No se pudo copiar {{name}} en {{destination}}",
"uploadFailedError": "Error al cargar {{name}}.",
"location": "Ubicación",
"locationAriaLabel": "Ubicación",
"selectLocation": "Seleccionar una ubicación de bloc de notas para copiar",
"name": "Nombre"
},
"publishNotebook": {
"publishFailedError": "No se pudo publicar {{notebookName}} en la galería",
"publishDescription": "Cuando se publique, este bloc de notas aparecerá en la galería pública de blocs de notas de Azure Cosmos DB. Asegúrese de que ha quitado los datos confidenciales o la salida antes de la publicación.",
"publishPrompt": "¿Desea publicar y compartir \"{{name}}\" en la galería?",
"coverImage": "Imagen de portada",
"coverImageUrl": "Dirección URL de la imagen de portada",
"name": "Nombre",
"description": "Descripción",
"tags": "Etiquetas",
"tagsPlaceholder": "Etiqueta opcional 1, etiqueta opcional 2",
"preview": "Versión preliminar",
"urlType": "URL",
"customImage": "Imagen personalizada",
"takeScreenshot": "Obtener recorte de pantalla",
"useFirstDisplayOutput": "Usar la primera salida de pantalla",
"failedToCaptureOutput": "No se pudo capturar la primera salida",
"outputDoesNotExist": "La salida no existe para ninguna de las celdas.",
"failedToConvertError": "No se pudo convertir {{fileName}} al formato base64",
"failedToUploadError": "No se pudo cargar {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "No se pudo iniciar el trabajo de transferencia de datos",
"suboptimalPartitionKeyError": "Advertencia: el sistema ha detectado que la colección puede estar usando una clave de partición poco óptima",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Ressources pédagogiques",
"nextSteps": "Étapes suivantes",
"tipsAndLearnMore": "Conseils et plus dinformations",
"notebook": "Bloc-notes",
"needHelp": "Avez-vous besoin daide ?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} créé(s), {{numThrottled}} limité(s), {{numFailed}} erreur(s)",
"uploadedFiles": "Fichiers chargés"
},
"copyNotebook": {
"copyFailedError": "Nous navons pas pu copier {{name}} vers {{destination}}",
"uploadFailedError": "Nous navons pas pu charger {{name}}",
"location": "Emplacement",
"locationAriaLabel": "Emplacement",
"selectLocation": "Sélectionner un emplacement de bloc-notes vers lequel effectuer une copie",
"name": "Nom"
},
"publishNotebook": {
"publishFailedError": "Nous navons pas pu publier {{notebookName}} dans la galerie",
"publishDescription": "Une fois publié, ce bloc-notes apparaîtra dans la galerie publique de bloc-notes dAzure Cosmos DB. Veillez à bien supprimer toutes les données sensibles et tout résultat avant la publication.",
"publishPrompt": "Voulez-vous publier et partager « {{name}} » dans la galerie ?",
"coverImage": "Image de couverture",
"coverImageUrl": "URL dimage de couverture",
"name": "Nom",
"description": "Description",
"tags": "Balises",
"tagsPlaceholder": "Balise facultative 1, Balise facultative 2",
"preview": "Aperçu",
"urlType": "URL",
"customImage": "Image personnalisée",
"takeScreenshot": "Prendre une capture d’écran",
"useFirstDisplayOutput": "Utiliser le résultat du premier affichage",
"failedToCaptureOutput": "Nous navons pas pu capturer le premier résultat",
"outputDoesNotExist": "Aucune des cellules ne présente de résultats.",
"failedToConvertError": "Nous navons pas pu convertir {{fileName}} au format base64",
"failedToUploadError": "Nous navons pas pu charger {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "Nous navons pas pu démarrer la tâche de transfert de données",
"suboptimalPartitionKeyError": "Avertissement : Le système a détecté que votre collection utilise peut-être une clé de partition sous-optimale",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Tanulási források",
"nextSteps": "Következő lépések",
"tipsAndLearnMore": "Tippek és további információ",
"notebook": "Jegyzetfüzet",
"needHelp": "Segítségre van szüksége?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} létrehozva, {{numThrottled}} szabályozva, {{numFailed}} hiba",
"uploadedFiles": "Feltöltött fájlok"
},
"copyNotebook": {
"copyFailedError": "Nem sikerült a(z) {{name}} másolása ide: {{destination}}",
"uploadFailedError": "Nem sikerült a(z) {{name}} feltöltése",
"location": "Hely",
"locationAriaLabel": "Hely",
"selectLocation": "Jegyzetfüzet másolási helyének kiválasztása",
"name": "Név"
},
"publishNotebook": {
"publishFailedError": "Nem sikerült a(z) {{notebookName}} közzététele a katalógusban",
"publishDescription": "Közzétételkor ez a jegyzetfüzet megjelenik a Azure Cosmos DB jegyzetfüzetek nyilvános katalógusában. A közzététel előtt győződjön meg arról, hogy eltávolította a bizalmas adatokat vagy kimeneteket.",
"publishPrompt": "Közzéteszi és megosztja a(z) {{name}} dokumentumot a katalógusban?",
"coverImage": "Borítókép",
"coverImageUrl": "Borítókép URL-címe",
"name": "Név",
"description": "Leírás",
"tags": "Címkék",
"tagsPlaceholder": "Nem kötelező címke 1, nem kötelező címke 2",
"preview": "Előzetes verzió",
"urlType": "URL-cím",
"customImage": "Egyéni rendszerkép",
"takeScreenshot": "Képernyőkép készítése",
"useFirstDisplayOutput": "Első megjelenítési kimenet használata",
"failedToCaptureOutput": "Nem sikerült rögzíteni az első kimenetet",
"outputDoesNotExist": "A kimenet nem létezik egyik cellához sem.",
"failedToConvertError": "Nem sikerült a(z) {{fileName}} base64 formátumra való konvertálása",
"failedToUploadError": "Nem sikerült a(z) {{fileName}} feltöltése"
},
"changePartitionKey": {
"failedToStartError": "Nem sikerült elindítani az adatátviteli feladatot",
"suboptimalPartitionKeyError": "Figyelmeztetés: A rendszer úgy észlelte, hogy a gyűjtemény valószínűleg nem optimális partíciókulcsot használ",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Sumber Daya Pembelajaran",
"nextSteps": "Langkah berikutnya",
"tipsAndLearnMore": "Tips & pelajari selengkapnya",
"notebook": "Buku catatan",
"needHelp": "Perlu bantuan?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} dibuat, {{numThrottled}} dibatasi, {{numFailed}} kesalahan",
"uploadedFiles": "File yang diunggah"
},
"copyNotebook": {
"copyFailedError": "Gagal menyalin {{name}} ke {{destination}}",
"uploadFailedError": "Gagal mengunggah {{name}}",
"location": "Lokasi",
"locationAriaLabel": "Lokasi",
"selectLocation": "Pilih lokasi buku catatan untuk disalin",
"name": "Nama"
},
"publishNotebook": {
"publishFailedError": "Gagal menerbitkan {{notebookName}} ke galeri",
"publishDescription": "Saat diterbitkan, buku catatan ini akan muncul di galeri publik buku catatan Azure Cosmos DB. Pastikan Anda telah menghapus data atau output sensitif sebelum menerbitkan.",
"publishPrompt": "Apakah Anda ingin menerbitkan dan membagikan \"{{name}}\" ke galeri?",
"coverImage": "Gambar sampul",
"coverImageUrl": "Url gambar sampul",
"name": "Nama",
"description": "Deskripsi",
"tags": "Tag",
"tagsPlaceholder": "Tag opsional 1, Tag opsional 2",
"preview": "Pratinjau",
"urlType": "URL",
"customImage": "Gambar Kustom",
"takeScreenshot": "Ambil Cuplikan Layar",
"useFirstDisplayOutput": "Gunakan Output Tampilan Pertama",
"failedToCaptureOutput": "Gagal mengambil output pertama",
"outputDoesNotExist": "Output tidak ada untuk sel mana pun.",
"failedToConvertError": "Gagal mengonversi {{fileName}} ke format base64",
"failedToUploadError": "Gagal mengunggah {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "Gagal memulai tugas transfer data",
"suboptimalPartitionKeyError": "Peringatan: Sistem mendeteksi bahwa koleksi Anda mungkin menggunakan kunci partisi yang kurang optimal",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Risorse di formazione",
"nextSteps": "Passaggi successivi",
"tipsAndLearnMore": "Suggerimenti e altre informazioni",
"notebook": "Notebook",
"needHelp": "Serve aiuto?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} creati, {{numThrottled}} con limitazione, {{numFailed}} errori",
"uploadedFiles": "File caricati"
},
"copyNotebook": {
"copyFailedError": "Non è stato possibile copiare {{name}} in {{destination}}",
"uploadFailedError": "Non è possibile caricare {{name}}",
"location": "Posizione",
"locationAriaLabel": "Posizione",
"selectLocation": "Selezionare una posizione del notebook in cui copiare",
"name": "Nome"
},
"publishNotebook": {
"publishFailedError": "Non è stato possibile pubblicare {{notebookName}} nella raccolta",
"publishDescription": "Quando viene pubblicato, questo notebook sarà visualizzato nella raccolta pubblica di Azure Cosmos DB. Assicurarsi di aver rimosso dati o output sensibili prima della pubblicazione.",
"publishPrompt": "Pubblicare e condividere \"{{name}}\" nella raccolta?",
"coverImage": "Immagine di copertina",
"coverImageUrl": "URL immagine di copertina",
"name": "Nome",
"description": "Descrizione",
"tags": "Tag",
"tagsPlaceholder": "Tag facoltativo 1, tag facoltativo 2",
"preview": "Anteprima",
"urlType": "URL",
"customImage": "Immagine personalizzata",
"takeScreenshot": "Crea screenshot",
"useFirstDisplayOutput": "Usa output prima visualizzazione",
"failedToCaptureOutput": "Non è stato possibile acquisire il primo output",
"outputDoesNotExist": "L'output non esiste per nessuna delle celle.",
"failedToConvertError": "Non è stato possibile convertire {{fileName}} nel formato base64",
"failedToUploadError": "Non è possibile caricare {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "Non è stato possibile avviare il processo di trasferimento dati",
"suboptimalPartitionKeyError": "Avviso: il sistema ha rilevato che la raccolta potrebbe usare una chiave di partizione non ottimale",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "学習リソース",
"nextSteps": "次の手順",
"tipsAndLearnMore": "ヒントと詳細の確認",
"notebook": "ノートブック",
"needHelp": "ヘルプが必要ですか?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} 件作成済み、{{numThrottled}} 件調整済み、{{numFailed}} 件のエラー",
"uploadedFiles": "ファイルをアップロードしました"
},
"copyNotebook": {
"copyFailedError": "{{name}} を {{destination}} にコピーできませんでした",
"uploadFailedError": "{{name}} をアップロードできませんでした",
"location": "場所",
"locationAriaLabel": "場所",
"selectLocation": "コピーするノートブックの場所を選択する",
"name": "名前"
},
"publishNotebook": {
"publishFailedError": "{{notebookName}} をギャラリーに発行できませんでした",
"publishDescription": "公開すると、このノートブックは Azure Cosmos DB ノートブックのパブリック ギャラリーに表示されます。公開前に機密データや出力が削除されていることを確認してください。",
"publishPrompt": "\"{{name}}\" をギャラリーに公開して共有しますか?",
"coverImage": "カバー画像",
"coverImageUrl": "カバー画像の URL",
"name": "名前",
"description": "説明",
"tags": "タグ",
"tagsPlaceholder": "オプションのタグ 1、オプションのタグ 2",
"preview": "プレビュー",
"urlType": "URL",
"customImage": "カスタム イメージ",
"takeScreenshot": "スクリーンショットを撮る",
"useFirstDisplayOutput": "最初のディスプレイ出力を使用する",
"failedToCaptureOutput": "最初の出力をキャプチャできませんでした",
"outputDoesNotExist": "どのセルにも出力が存在しません。",
"failedToConvertError": "{{fileName}} を base64 形式に変換できませんでした",
"failedToUploadError": "{{fileName}} をアップロードできませんでした"
},
"changePartitionKey": {
"failedToStartError": "データ転送ジョブの開始に失敗しました",
"suboptimalPartitionKeyError": "警告: システムはコレクションが最適でないパーティション キーを使用している可能性を検出しました",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "학습 리소스",
"nextSteps": "다음 단계",
"tipsAndLearnMore": "팁 및 자세한 정보",
"notebook": "Notebook",
"needHelp": "도움이 필요하세요?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} 생성됨, {{numThrottled}} 제한됨, {{numFailed}} 오류 발생",
"uploadedFiles": "업로드된 파일"
},
"copyNotebook": {
"copyFailedError": "{{name}}을(를) {{destination}}(으)로 복사 실패",
"uploadFailedError": "'{{name}}' 업로드 실패",
"location": "위치",
"locationAriaLabel": "위치",
"selectLocation": "복사할 노트북 위치 선택",
"name": "이름"
},
"publishNotebook": {
"publishFailedError": "{{notebookName}}을(를) 갤러리에 게시하지 못했습니다.",
"publishDescription": "게시하면 이 노트북이 Azure Cosmos DB 노트북 공개 갤러리에 표시됩니다. 게시 전에 민감한 데이터나 출력이 제거되었는지 확인하세요.",
"publishPrompt": "\"{{name}}\"을(를) 게시하고 갤러리에 공유하시겠습니까?",
"coverImage": "커버 이미지",
"coverImageUrl": "표지 이미지 URL",
"name": "이름",
"description": "설명",
"tags": "태그",
"tagsPlaceholder": "선택 태그 1, 선택 태그 2",
"preview": "미리 보기",
"urlType": "URL",
"customImage": "사용자 지정 이미지",
"takeScreenshot": "화면 캡처",
"useFirstDisplayOutput": "첫 번째 디스플레이 출력 사용",
"failedToCaptureOutput": "첫 번째 출력을 캡처하지 못했습니다.",
"outputDoesNotExist": "셀에 대한 출력이 없습니다.",
"failedToConvertError": "{{fileName}}을(를) base64 형식으로 변환하지 못했습니다.",
"failedToUploadError": "{{fileName}} 업로드 실패"
},
"changePartitionKey": {
"failedToStartError": "데이터 전송 작업을 시작하지 못했습니다.",
"suboptimalPartitionKeyError": "경고: 컬렉션이 최적이 아닌 파티션 키를 사용하고 있을 수 있습니다.",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Trainingsresources",
"nextSteps": "Volgende stappen",
"tipsAndLearnMore": "Tips & meer informatie",
"notebook": "Notitieboek",
"needHelp": "Hulp nodig?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} gemaakt, {{numThrottled}} beperkt, {{numFailed}} fouten",
"uploadedFiles": "Geüploade bestanden"
},
"copyNotebook": {
"copyFailedError": "{{name}} kopiëren naar {{destination}} is mislukt",
"uploadFailedError": "Kan {{name}} niet uploaden",
"location": "Locatie",
"locationAriaLabel": "Locatie",
"selectLocation": "Notebooklocatie selecteren om te kopiëren",
"name": "Naam"
},
"publishNotebook": {
"publishFailedError": "{{notebookName}} publiceren naar galerie is mislukt",
"publishDescription": "Wanneer deze notebook wordt gepubliceerd, wordt het weergegeven in de Azure Cosmos DB notebooks openbaar galerie. Zorg ervoor dat u gevoelige gegevens of uitvoer hebt verwijderd voordat u publiceert.",
"publishPrompt": "Wilt u {{name}} publiceren en delen in de galerie?",
"coverImage": "Omslagafbeelding",
"coverImageUrl": "URL van omslagafbeelding",
"name": "Naam",
"description": "Beschrijving",
"tags": "Tags",
"tagsPlaceholder": "Optionele tag 1, optionele tag 2",
"preview": "Preview",
"urlType": "URL",
"customImage": "Aangepaste installatiekopie",
"takeScreenshot": "Schermopname maken",
"useFirstDisplayOutput": "Gebruik uitvoer van eerste weergave",
"failedToCaptureOutput": "Kan de eerste uitvoer niet vastleggen",
"outputDoesNotExist": "Uitvoer bestaat niet voor alle cellen.",
"failedToConvertError": "{{fileName}} converteren naar base64-indeling is mislukt",
"failedToUploadError": "Kan {{fileName}} niet uploaden"
},
"changePartitionKey": {
"failedToStartError": "Kan de taak voor gegevensoverdracht niet starten",
"suboptimalPartitionKeyError": "Waarschuwing: het systeem heeft gedetecteerd dat uw verzameling mogelijk een suboptimale partitiesleutel gebruikt",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Zasoby szkoleniowe",
"nextSteps": "Następne kroki",
"tipsAndLearnMore": "Porady i dowiedz się więcej",
"notebook": "Notes",
"needHelp": "Potrzebujesz pomocy?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "Utworzono: {{numSucceeded}}, ograniczono: {{numThrottled}}, błędy: {{numFailed}}",
"uploadedFiles": "Przekazywane pliki"
},
"copyNotebook": {
"copyFailedError": "Nie można skopiować {{name}} do {{destination}}",
"uploadFailedError": "Nie można przekazać {{name}}",
"location": "Lokalizacja",
"locationAriaLabel": "Lokalizacja",
"selectLocation": "Wybierz lokalizację notesu do skopiowania",
"name": "Nazwa"
},
"publishNotebook": {
"publishFailedError": "Nie można opublikować {{notebookName}} w galerii",
"publishDescription": "Po opublikowaniu ten notes pojawi się w publicznej galerii notesów Azure Cosmos DB. Przed opublikowaniem upewnij się, że usunięto poufne dane lub dane wyjściowe.",
"publishPrompt": "Czy chcesz opublikować i udostępnić „{{name}}” w galerii?",
"coverImage": "Obraz okładki",
"coverImageUrl": "Adres URL obrazu tytułowego",
"name": "Nazwa",
"description": "Opis",
"tags": "Tagi",
"tagsPlaceholder": "Opcjonalny tag 1, opcjonalny tag 2",
"preview": "Podgląd",
"urlType": "Adres URL",
"customImage": "Obraz niestandardowy",
"takeScreenshot": "Zrób zrzut ekranu",
"useFirstDisplayOutput": "Użyj pierwszego wyświetlania danych wyjściowych",
"failedToCaptureOutput": "Nie można przechwycić pierwszych danych wyjściowych",
"outputDoesNotExist": "Dane wyjściowe nie istnieją dla żadnej komórki.",
"failedToConvertError": "Nie można przekonwertować {{fileName}} na format base64",
"failedToUploadError": "Nie można przekazać {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "Nie udało się uruchomić zadania transferu danych",
"suboptimalPartitionKeyError": "Ostrzeżenie: system wykrył, że kolekcja może używać nieoptymalnego klucza partycji",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Recursos de aprendizado",
"nextSteps": "Próximas etapas",
"tipsAndLearnMore": "Dicas e saiba mais",
"notebook": "Notebook",
"needHelp": "Precisa de ajuda?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} criado(s), {{numThrottled}} limitado(s), {{numFailed}} erro(s)",
"uploadedFiles": "Arquivos carregados"
},
"copyNotebook": {
"copyFailedError": "Falha ao copiar {{name}} para {{destination}}",
"uploadFailedError": "Falha ao carregar {{name}}",
"location": "Localização",
"locationAriaLabel": "Localização",
"selectLocation": "Selecione um local do notebook para copiar",
"name": "Nome"
},
"publishNotebook": {
"publishFailedError": "Falha ao publicar {{notebookName}} na galeria",
"publishDescription": "Quando publicado, esse notebook aparecerá na galeria pública de notebooks do Azure Cosmos DB. Verifique se você removeu os dados confidenciais ou a saída antes de publicar.",
"publishPrompt": "Deseja publicar e compartilhar \"{{name}}\" na galeria?",
"coverImage": "Imagem de capa",
"coverImageUrl": "URL da imagem de capa",
"name": "Nome",
"description": "Descrição",
"tags": "Rótulos",
"tagsPlaceholder": "Marca opcional 1, marca opcional 2",
"preview": "Visualizar",
"urlType": "URL",
"customImage": "Imagem Personalizada",
"takeScreenshot": "Capturar Tela",
"useFirstDisplayOutput": "Usar a Primeira Saída de Exibição",
"failedToCaptureOutput": "Falha ao capturar a primeira saída",
"outputDoesNotExist": "A saída não existe para nenhuma das células.",
"failedToConvertError": "Falha ao converter {{fileName}} no formato base64",
"failedToUploadError": "Falha ao carregar {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "Falha ao iniciar o trabalho de transferência de dados",
"suboptimalPartitionKeyError": "Aviso: o sistema detectou que sua coleção pode estar usando uma chave de partição abaixo do ideal",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Recursos de Aprendizagem",
"nextSteps": "Passos seguintes",
"tipsAndLearnMore": "Sugestões e saiba mais",
"notebook": "Bloco de notas",
"needHelp": "Precisa de ajuda?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} criados, {{numThrottled}} limitados, {{numFailed}} erros",
"uploadedFiles": "Ficheiros carregados"
},
"copyNotebook": {
"copyFailedError": "Falha ao copiar {{name}} para {{destination}}",
"uploadFailedError": "Não foi possível carregar {{name}}",
"location": "Localização",
"locationAriaLabel": "Localização",
"selectLocation": "Selecione uma localização de bloco de notas para copiar",
"name": "Nome"
},
"publishNotebook": {
"publishFailedError": "Falha ao publicar {{notebookName}} na galeria",
"publishDescription": "Quando publicado, este bloco de notas será apresentado na galeria pública de blocos de notas do Azure Cosmos DB. Certifique-se de que removeu quaisquer dados confidenciais ou resultados antes de publicar.",
"publishPrompt": "Pretende publicar e partilhar \"{{name}}\" na galeria?",
"coverImage": "Imagem de capa",
"coverImageUrl": "URL da imagem de capa",
"name": "Nome",
"description": "Descrição",
"tags": "Sinalizadores",
"tagsPlaceholder": "Etiqueta opcional 1, Etiqueta opcional 2",
"preview": "Pré-visualização",
"urlType": "URL",
"customImage": "Imagem Personalizada",
"takeScreenshot": "Tirar Captura de Ecrã",
"useFirstDisplayOutput": "Utilizar Saída do Primeiro Ecrã",
"failedToCaptureOutput": "Falha ao capturar a primeira saída",
"outputDoesNotExist": "A saída não existe para nenhuma das células.",
"failedToConvertError": "Falha ao converter {{fileName}} para o formato base64",
"failedToUploadError": "Não foi possível carregar {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "Falha ao iniciar a tarefa de transferência de dados",
"suboptimalPartitionKeyError": "Aviso: O sistema detetou que a sua coleção pode estar a utilizar uma chave de partição não ideal.",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Учебные материалы",
"nextSteps": "Дальнейшие действия",
"tipsAndLearnMore": "Советы и дополнительная информация",
"notebook": "Записная книжка",
"needHelp": "Нужна помощь?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "Создано: {{numSucceeded}}, отклонено в результате регулирования: {{numThrottled}}, ошибок: {{numFailed}}",
"uploadedFiles": "Отправленные файлы"
},
"copyNotebook": {
"copyFailedError": "Не удалось скопировать {{name}} в {{destination}}",
"uploadFailedError": "Не удалось отправить {{name}}",
"location": "Расположение",
"locationAriaLabel": "Расположение",
"selectLocation": "Выберите место для копирования записной книжки",
"name": "Имя"
},
"publishNotebook": {
"publishFailedError": "Не удалось опубликовать {{notebookName}} в галерее",
"publishDescription": "После публикации эта записная книжка появится в общедоступной галерее записных книжек Azure Cosmos DB. Перед публикацией убедитесь, что удалили все конфиденциальные данные и результаты.",
"publishPrompt": "Хотите опубликовать \"{{name}}\" и поделиться ею в галерее?",
"coverImage": "Изображение обложки",
"coverImageUrl": "URL-адрес изображения обложки",
"name": "Имя",
"description": "Описание",
"tags": "Теги",
"tagsPlaceholder": "Необязательный тег 1, необязательный тег 2",
"preview": "Предварительный просмотр",
"urlType": "URL-адрес",
"customImage": "Пользовательское изображение",
"takeScreenshot": "Сделать снимок экрана",
"useFirstDisplayOutput": "Использовать вывод первого дисплея",
"failedToCaptureOutput": "Не удалось зафиксировать первый выданный результат",
"outputDoesNotExist": "Выданный результат отсутствует для всех ячеек.",
"failedToConvertError": "Не удалось преобразовать {{fileName}} в формат base64",
"failedToUploadError": "Не удалось отправить {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "Не удалось запустить задание передачи данных",
"suboptimalPartitionKeyError": "Внимание! Система обнаружила, что в вашей коллекции используется неоптимальный ключ секционирования",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Utbildningsresurser",
"nextSteps": "Nästa steg",
"tipsAndLearnMore": "Tips och läs mer",
"notebook": "Anteckningsbok",
"needHelp": "Behöver du hjälp?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} skapades, {{numThrottled}} begränsades, {{numFailed}} fel",
"uploadedFiles": "Uppladdade filer"
},
"copyNotebook": {
"copyFailedError": "Det gick inte att kopiera {{name}} till {{destination}}",
"uploadFailedError": "Det gick inte att ladda upp {{name}}",
"location": "Plats",
"locationAriaLabel": "Plats",
"selectLocation": "Välj en plats för anteckningsbok att kopiera",
"name": "Namn"
},
"publishNotebook": {
"publishFailedError": "Det gick inte att publicera {{notebookName}} till galleriet",
"publishDescription": "När den här anteckningsboken publiceras visas den i det offentliga galleriet för Azure Cosmos DB notebook-filer. Kontrollera att du har tagit bort känsliga data eller utdata innan du publicerar.",
"publishPrompt": "Vill du publicera och dela {{name}} till galleriet?",
"coverImage": "Omslagsbild",
"coverImageUrl": "URL för omslagsbild",
"name": "Namn",
"description": "Beskrivning",
"tags": "Taggar",
"tagsPlaceholder": "Valfri tagg 1, valfri tagg 2",
"preview": "Förhandsversion",
"urlType": "Webbadress",
"customImage": "Anpassad avbildning",
"takeScreenshot": "Ta skärmbild",
"useFirstDisplayOutput": "Använd första visningsutdata",
"failedToCaptureOutput": "Det gick inte att samla in första utdata",
"outputDoesNotExist": "Utdata finns inte för någon av cellerna.",
"failedToConvertError": "Det gick inte att konvertera {{fileName}} till base64-format",
"failedToUploadError": "Det gick inte att ladda upp {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "Det gick inte att starta dataöverföringsjobbet",
"suboptimalPartitionKeyError": "Varning! Systemet har upptäckt att din samling kanske använder en suboptimal partitionsnyckel",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "Öğrenme Kaynakları",
"nextSteps": "Sonraki adımlar",
"tipsAndLearnMore": "İpuçları & daha fazla bilgi edinin",
"notebook": "Not Defteri",
"needHelp": "Yardıma mı ihtiyacınız var?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} oluşturuldu, {{numThrottled}} kısıtlandı, {{numFailed}} hata",
"uploadedFiles": "Karşıya yüklenen dosyalar"
},
"copyNotebook": {
"copyFailedError": "{{name}} öğesi {{destination}} hedefine kopyalanamadı",
"uploadFailedError": "{{name}} karşıya yüklenemedi",
"location": "Konum",
"locationAriaLabel": "Konum",
"selectLocation": "Kopyalamak için bir defter konumu seçin",
"name": "Ad"
},
"publishNotebook": {
"publishFailedError": "{{notebookName}} galeride yayımlanamadı",
"publishDescription": "Yayımlandığında, bu not defteri Azure Cosmos DB not defterleri genel galerisinde görünür. Yayımlamadan önce hassas verileri veya çıktıları kaldırdığınızdan emin olun.",
"publishPrompt": "“{{name}}” öğesini galeride yayımlamak ve paylaşmak istiyor musunuz?",
"coverImage": "Kapak resmi",
"coverImageUrl": "Kapak resmi URLsi",
"name": "Ad",
"description": "Açıklama",
"tags": "Etiketler",
"tagsPlaceholder": "İsteğe bağlı etiket 1, İsteğe bağlı etiket 2",
"preview": "Önizleme",
"urlType": "URL",
"customImage": "Özel Görüntü",
"takeScreenshot": "Ekran Görüntüsü Al",
"useFirstDisplayOutput": "İlk Görüntü Çıkışını Kullan",
"failedToCaptureOutput": "İlk çıkış yakalanamadı",
"outputDoesNotExist": "Hiçbir hücre için çıkış yok.",
"failedToConvertError": "{{fileName}} base64 biçimine dönüştürülemedi",
"failedToUploadError": "{{fileName}} karşıya yüklenemedi"
},
"changePartitionKey": {
"failedToStartError": "Veri aktarım işi başlatılamadı",
"suboptimalPartitionKeyError": "Uyarı: Sistem, koleksiyonunuzun optimal olmayan bir bölüm anahtarı kullanıyor olabileceğini algıladı",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "学习资源",
"nextSteps": "后续步骤",
"tipsAndLearnMore": "提示和详细信息",
"notebook": "笔记本",
"needHelp": "需要帮助?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} 已创建,{{numThrottled}} 受限,{{numFailed}} 个错误",
"uploadedFiles": "已上传的文件"
},
"copyNotebook": {
"copyFailedError": "未能将 {{name}} 复制到 {{destination}}",
"uploadFailedError": "未能上传 {{name}}",
"location": "位置",
"locationAriaLabel": "位置",
"selectLocation": "选择要复制的笔记本位置",
"name": "名称"
},
"publishNotebook": {
"publishFailedError": "未能将 {{notebookName}} 发布到库",
"publishDescription": "发布后,此笔记本将显示在 Azure Cosmos DB 笔记本公共库中。在发布之前,请确保已移除任何敏感数据或输出。",
"publishPrompt": "是否要发布“{{name}}”并共享到库?",
"coverImage": "封面图像",
"coverImageUrl": "封面图像 URL",
"name": "名称",
"description": "说明",
"tags": "标记",
"tagsPlaceholder": "可选标记 1,可选标记 2",
"preview": "预览",
"urlType": "URL",
"customImage": "自定义映像",
"takeScreenshot": "生成屏幕快照",
"useFirstDisplayOutput": "使用第一个显示输出",
"failedToCaptureOutput": "未能捕获第一个输出",
"outputDoesNotExist": "任何单元格都不存在输出。",
"failedToConvertError": "未能将 {{fileName}} 转换为 base64 格式",
"failedToUploadError": "未能上传 {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "未能启动数据传输作业",
"suboptimalPartitionKeyError": "警告: 系统检测到集合使用的分区键可能不理想",
-29
View File
@@ -103,7 +103,6 @@
"learningResources": "學習資源",
"nextSteps": "後續步驟",
"tipsAndLearnMore": "提示與深入了解",
"notebook": "筆記本",
"needHelp": "是否需要協助?"
},
"top3Items": {
@@ -664,34 +663,6 @@
"uploadStatus": "{{numSucceeded}} 個已建立,{{numThrottled}} 個已節流,{{numFailed}} 個錯誤",
"uploadedFiles": "上傳的檔案"
},
"copyNotebook": {
"copyFailedError": "無法將 {{name}} 複製到 {{destination}}",
"uploadFailedError": "無法上傳 {{name}}",
"location": "位置",
"locationAriaLabel": "位置",
"selectLocation": "選取要複製的筆記本位置",
"name": "名稱"
},
"publishNotebook": {
"publishFailedError": "無法將 {{notebookName}} 發佈至資源庫",
"publishDescription": "發佈後,此筆記本會出現在 Azure Cosmos DB 筆記本公用資源庫中。發佈前,請確定已移除任何敏感性資料或輸出。",
"publishPrompt": "您是否要發佈並共用 \"{{name}}\" 至資源庫?",
"coverImage": "封面影像",
"coverImageUrl": "封面影像 URL",
"name": "名稱",
"description": "描述",
"tags": "標籤",
"tagsPlaceholder": "選用標記 1,選用標記 2",
"preview": "預覽",
"urlType": "URL",
"customImage": "自訂映像",
"takeScreenshot": "擷取螢幕擷取畫面",
"useFirstDisplayOutput": "使用第一個顯示輸出",
"failedToCaptureOutput": "無法擷取第一個輸出",
"outputDoesNotExist": "任何儲存格的輸出都不存在。",
"failedToConvertError": "無法將 {{fileName}} 轉換為 base64 格式",
"failedToUploadError": "無法上傳 {{fileName}}"
},
"changePartitionKey": {
"failedToStartError": "無法啟動資料傳輸工作",
"suboptimalPartitionKeyError": "警告: 系統偵測到您的集合可能在使用次佳的資料分割索引鍵",
+6 -9
View File
@@ -2,21 +2,18 @@ import { extractFeatures, hasFlag } from "./extractFeatures";
describe("extractFeatures", () => {
it("correctly detects feature flags in a case insensitive manner", () => {
const url = "https://localhost:10001/12345/notebook";
const token = "super secret";
const notebooksEnabled = false;
const endpoint = "https://localhost:1234";
const ttlEnabled = false;
const params = new URLSearchParams({
platform: "Hosted",
"feature.NOTEBOOKSERVERURL": url,
"feature.NoTeBooKServerToken": token,
"feature.MONGOPROXYENDPOINT": endpoint,
"feature.NotAFeature": "nope",
"feature.ENABLEnotebooks": notebooksEnabled.toString(),
"feature.ENABLEttl": ttlEnabled.toString(),
});
const features = extractFeatures(params);
expect(features.notebookServerUrl).toBe(url);
expect(features.notebookServerToken).toBe(token);
expect(features.enableNotebooks).toBe(notebooksEnabled);
expect(features.mongoProxyEndpoint).toBe(endpoint);
expect(features.enableTtl).toBe(ttlEnabled);
});
});
-20
View File
@@ -5,10 +5,8 @@ export type Features = {
readonly enableChangeFeedPolicy: boolean;
readonly enableFixedCollectionWithSharedThroughput: boolean;
readonly enableKOPanel: boolean;
readonly enableNotebooks: boolean;
readonly enableReactPane: boolean;
readonly enableRightPanelV2: boolean;
readonly enableSchema: boolean;
readonly enableSDKoperations: boolean;
readonly enableSpark: boolean;
readonly enableTtl: boolean;
@@ -18,12 +16,6 @@ export type Features = {
readonly enableKoResourceTree: boolean;
readonly enableThroughputBuckets: boolean;
readonly hostedDataExplorer: boolean;
readonly junoEndpoint?: string;
readonly phoenixEndpoint?: string;
readonly notebookBasePath?: string;
readonly notebookServerToken?: string;
readonly notebookServerUrl?: string;
readonly sandboxNotebookOutputs: boolean;
readonly selfServeType?: string;
readonly showMinRUSurvey: boolean;
readonly ttl90Days: boolean;
@@ -43,9 +35,6 @@ export type Features = {
autoscaleDefault: boolean;
partitionKeyDefault: boolean;
partitionKeyDefault2: boolean;
phoenixNotebooks?: boolean;
phoenixFeatures?: boolean;
notebooksDownBanner: boolean;
};
export function extractFeatures(given = new URLSearchParams(window.location.search)): Features {
@@ -72,10 +61,8 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
enableChangeFeedPolicy: "true" === get("enablechangefeedpolicy"),
enableFixedCollectionWithSharedThroughput: "true" === get("enablefixedcollectionwithsharedthroughput"),
enableKOPanel: "true" === get("enablekopanel"),
enableNotebooks: "true" === get("enablenotebooks"),
enableReactPane: "true" === get("enablereactpane"),
enableRightPanelV2: "true" === get("enablerightpanelv2"),
enableSchema: "true" === get("enableschema"),
enableSDKoperations: "true" === get("enablesdkoperations"),
enableSpark: "true" === get("enablespark"),
enableTtl: "true" === get("enablettl"),
@@ -85,19 +72,12 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
hostedDataExplorer: "true" === get("hosteddataexplorerenabled"),
mongoProxyEndpoint: get("mongoproxyendpoint"),
mongoProxyAPIs: get("mongoproxyapis"),
junoEndpoint: get("junoendpoint"),
phoenixEndpoint: get("phoenixendpoint"),
notebookBasePath: get("notebookbasepath"),
notebookServerToken: get("notebookservertoken"),
notebookServerUrl: get("notebookserverurl"),
sandboxNotebookOutputs: true,
selfServeType: get("selfservetype"),
showMinRUSurvey: "true" === get("showminrusurvey"),
ttl90Days: "true" === get("ttl90days"),
autoscaleDefault: "true" === get("autoscaledefault"),
partitionKeyDefault: "true" === get("partitionkeytest"),
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
notebooksDownBanner: "true" === get("notebooksDownBanner"),
enableThroughputCap: "true" === get("enablethroughputcap"),
enableHierarchicalKeys: "true" === get("enablehierarchicalkeys"),
enablePriorityBasedExecution: "true" === get("enableprioritybasedexecution"),
@@ -53,6 +53,7 @@ export enum Action {
SubscriptionSwitch,
TenantSwitch,
DefaultTenantSwitch,
// Deprecated notebook telemetry tombstones. Keep these members to preserve all later numeric values.
CreateNotebookWorkspace,
NotebookErrorNotification,
CreateSparkCluster,
@@ -62,6 +63,7 @@ export enum Action {
ClusterLibraryManage,
ModifyOptionForThroughputWithSharedDatabase,
EnableAzureSynapseLink,
// Deprecated notebook and Phoenix telemetry tombstones.
CreateNewNotebook,
OpenSampleNotebook,
ExecuteCell,
@@ -93,12 +95,14 @@ export enum Action {
OpenCloudShellTerminal,
CreateMongoCollectionWithWildcardIndex,
ClickCommandBarButton,
// Deprecated notebook telemetry tombstone.
RefreshResourceTreeMyNotebooks,
ClickResourceTreeNodeContextMenuItem,
DiscardSettings,
SettingsV2Updated,
SettingsV2Discarded,
MongoIndexUpdated,
// Deprecated notebook gallery telemetry tombstones.
NotebooksGalleryPublish,
NotebooksGalleryReportAbuse,
NotebooksGalleryClickReportAbuse,
@@ -124,6 +128,7 @@ export enum Action {
SelfServe,
ExpandAddCollectionPaneAdvancedSection,
ExpandAddGlobalSecondaryIndexPaneAdvancedSection,
// Deprecated Schema Analyzer telemetry tombstone.
SchemaAnalyzerClickAnalyze,
SelfServeComponent,
LaunchQuickstart,
@@ -154,6 +159,7 @@ export enum Action {
ReadDatabases,
ReadCollections,
LoadCollectionsPerDatabase,
// Deprecated notebook and Phoenix telemetry tombstones.
RefreshNotebooksEnabled,
CheckPhoenixStatus,
CheckFeatureRegistration,
-4
View File
@@ -24,10 +24,8 @@ describe("AuthorizationUtils", () => {
enableChangeFeedPolicy: false,
enableFixedCollectionWithSharedThroughput: false,
enableKOPanel: false,
enableNotebooks: false,
enableReactPane: false,
enableRightPanelV2: false,
enableSchema: false,
enableSDKoperations: false,
enableSpark: false,
enableTtl: false,
@@ -36,7 +34,6 @@ describe("AuthorizationUtils", () => {
enableKoResourceTree: false,
enableThroughputBuckets: false,
hostedDataExplorer: false,
sandboxNotebookOutputs: true,
showMinRUSurvey: false,
ttl90Days: false,
enableThroughputCap: false,
@@ -47,7 +44,6 @@ describe("AuthorizationUtils", () => {
autoscaleDefault: false,
partitionKeyDefault: false,
partitionKeyDefault2: false,
notebooksDownBanner: false,
enableRestoreContainer: false,
mongoDisableNativeAuth: false,
},
+1 -12
View File
@@ -1,4 +1,4 @@
import { CassandraProxyEndpoints, JunoEndpoints, MongoProxyEndpoints, PortalBackendEndpoints } from "Common/Constants";
import { CassandraProxyEndpoints, MongoProxyEndpoints, PortalBackendEndpoints } from "Common/Constants";
import * as Logger from "../Common/Logger";
export function validateEndpoint(
@@ -89,14 +89,3 @@ export const allowedHostedExplorerEndpoints: ReadonlyArray<string> = [
];
export const allowedMsalRedirectEndpoints: ReadonlyArray<string> = ["https://dataexplorer-preview.azurewebsites.net/"];
export const allowedJunoOrigins: ReadonlyArray<string> = [
JunoEndpoints.Test,
JunoEndpoints.Test2,
JunoEndpoints.Test3,
JunoEndpoints.Prod,
JunoEndpoints.Stage,
"https://localhost",
];
export const allowedNotebookServerUrls: ReadonlyArray<string> = [];
@@ -1,88 +0,0 @@
/*
AUTOGENERATED FILE
Run "npm run generateARMClients" to regenerate
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2021-04-15/notebook.json
*/
import { configContext } from "../../../../ConfigContext";
import { armRequest } from "../../request";
import * as Types from "./types";
const apiVersion = "2021-04-15";
/* Gets the notebook workspace resources of an existing Cosmos DB account. */
export async function listByDatabaseAccount(
subscriptionId: string,
resourceGroupName: string,
accountName: string,
): Promise<Types.NotebookWorkspaceListResult> {
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces`;
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
}
/* Gets the notebook workspace for a Cosmos DB account. */
export async function get(
subscriptionId: string,
resourceGroupName: string,
accountName: string,
notebookWorkspaceName: string,
): Promise<Types.NotebookWorkspace> {
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`;
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "GET", apiVersion });
}
/* Creates the notebook workspace for a Cosmos DB account. */
export async function createOrUpdate(
subscriptionId: string,
resourceGroupName: string,
accountName: string,
notebookWorkspaceName: string,
): Promise<Types.NotebookWorkspace> {
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`;
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "PUT", apiVersion, body: {} });
}
/* Deletes the notebook workspace for a Cosmos DB account. */
export async function destroy(
subscriptionId: string,
resourceGroupName: string,
accountName: string,
notebookWorkspaceName: string,
): Promise<void> {
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}`;
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "DELETE", apiVersion });
}
/* Retrieves the connection info for the notebook workspace */
export async function listConnectionInfo(
subscriptionId: string,
resourceGroupName: string,
accountName: string,
notebookWorkspaceName: string,
): Promise<Types.NotebookWorkspaceConnectionInfoResult> {
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}/listConnectionInfo`;
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
}
/* Regenerates the auth token for the notebook workspace */
export async function regenerateAuthToken(
subscriptionId: string,
resourceGroupName: string,
accountName: string,
notebookWorkspaceName: string,
): Promise<void> {
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}/regenerateAuthToken`;
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
}
/* Starts the notebook workspace */
export async function start(
subscriptionId: string,
resourceGroupName: string,
accountName: string,
notebookWorkspaceName: string,
): Promise<void> {
const path = `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.DocumentDB/databaseAccounts/${accountName}/notebookWorkspaces/${notebookWorkspaceName}/start`;
return armRequest({ host: configContext.ARM_ENDPOINT, path, method: "POST", apiVersion });
}
@@ -1,40 +0,0 @@
/*
AUTOGENERATED FILE
Run "npm run generateARMClients" to regenerate
Edting this file directly should be done with extreme caution as not to diverge from ARM REST specs
Generated from: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/master/specification/cosmos-db/resource-manager/Microsoft.DocumentDB/stable/2021-04-15/notebook.json
*/
import { ARMResourceProperties } from "../cosmos/types";
/* Parameters to create a notebook workspace resource */
export type NotebookWorkspaceCreateUpdateParameters = unknown;
/* A list of notebook workspace resources */
export interface NotebookWorkspaceListResult {
/* Array of notebook workspace resources */
value?: NotebookWorkspace[];
}
/* A notebook workspace resource */
export type NotebookWorkspace = ARMResourceProperties & {
/* Resource properties. */
properties?: NotebookWorkspaceProperties;
};
/* Properties of a notebook workspace resource. */
export interface NotebookWorkspaceProperties {
/* Specifies the endpoint of Notebook server. */
readonly notebookServerEndpoint?: string;
/* Status of the notebook workspace. Possible values are: Creating, Online, Deleting, Failed, Updating. */
readonly status?: string;
}
/* The connection info for the given notebook workspace */
export interface NotebookWorkspaceConnectionInfoResult {
/* Specifies auth token used for connecting to Notebook server (uses token-based auth). */
readonly authToken?: string;
/* Specifies the endpoint of Notebook server. */
readonly notebookServerEndpoint?: string;
}