Compare commits

..

3 Commits

Author SHA1 Message Date
dependabot[bot]
0374ee48a5 Bump simple-get from 3.1.0 to 3.1.1
Bumps [simple-get](https://github.com/feross/simple-get) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/feross/simple-get/releases)
- [Commits](https://github.com/feross/simple-get/compare/v3.1.0...v3.1.1)

---
updated-dependencies:
- dependency-name: simple-get
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-25 20:01:44 +00:00
Armando Trejo Oliver
496f596f38 Fix Parent Origin Regex (#1239)
Not all regex are escaped properly
2022-03-25 12:59:18 -07:00
Mathieu Tremblay
d1587ef033 Update Tab title from 'Items' to id + ' - Items' to make it easier to differentiate (#1233) 2022-03-11 15:50:44 -05:00
17 changed files with 31416 additions and 1032 deletions

31969
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -86,7 +86,6 @@
"react-dnd": "14.0.2",
"react-dnd-html5-backend": "14.0.0",
"react-dom": "16.13.1",
"react-dropzone": "12.0.4",
"react-hotkeys": "2.0.0",
"react-i18next": "11.8.5",
"react-notification-system": "0.2.17",

View File

@@ -52,10 +52,10 @@ let configContext: Readonly<ConfigContext> = {
allowedParentFrameOrigins: [
`^https:\\/\\/cosmos\\.azure\\.(com|cn|us)$`,
`^https:\\/\\/[\\.\\w]*portal\\.azure\\.(com|cn|us)$`,
`^https:\\/\\/[\\.\\w]*portal\\.microsoftazure.de$`,
`^https:\\/\\/[\\.\\w]*portal\\.microsoftazure\\.de$`,
`^https:\\/\\/[\\.\\w]*ext\\.azure\\.(com|cn|us)$`,
`^https:\\/\\/[\\.\\w]*\\.ext\\.microsoftazure\\.de$`,
`^https://cosmos-db-dataexplorer-germanycentral.azurewebsites.de$`,
`^https:\\/\\/cosmos-db-dataexplorer-germanycentral\\.azurewebsites\\.de$`,
], // Webpack injects this at build time
gitSha: process.env.GIT_SHA,
hostedExplorerURL: "https://cosmos.azure.com/",

View File

@@ -9,7 +9,6 @@ export enum TabKind {
Graph,
SQLQuery,
ScaleSettings,
DataUploader,
}
/**

View File

@@ -142,7 +142,6 @@ export interface Collection extends CollectionBase {
onGraphDocumentsClick(): void;
onMongoDBDocumentsClick(): void;
onSchemaAnalyzerClick(): void;
onDataUploaderClick(): void;
openTab(): void;
onSettingsClick: () => Promise<void>;
@@ -365,7 +364,6 @@ export enum CollectionTabKind {
CollectionSettingsV2 = 20,
DatabaseSettingsV2 = 21,
SchemaAnalyzer = 22,
DataUploader = 23,
}
export enum TerminalKind {

View File

@@ -1,5 +0,0 @@
.dataUploader {
width: 100%;
height: 100%;
overflow-y: auto;
}

View File

@@ -1,209 +0,0 @@
import { ImmutableOutput } from "@nteract/commutable";
import { actions, AppState, ContentRef, KernelRef, selectors } from "@nteract/core";
import Immutable from "immutable";
import React, { CSSProperties, useCallback, useMemo } from "react";
import { useDropzone } from "react-dropzone";
import { connect } from "react-redux";
import { Dispatch } from "redux";
import "./DataUploader.less";
interface DataUploaderPureProps {
contentRef: ContentRef;
kernelRef: KernelRef;
databaseId: string;
collectionId: string;
}
const getColor = (props) => {
if (props.isDragAccept) {
return "#00e676";
}
if (props.isDragReject) {
return "#ff1744";
}
if (props.isFocused) {
return "#2196f3";
}
return "#eeeeee";
};
interface DataUploaderDispatchProps {
runCell: (contentRef: ContentRef, cellId: string) => void;
addTransform: (transform: React.ComponentType & { MIMETYPE: string }) => void;
updateCell: (text: string, id: string, contentRef: ContentRef) => void;
}
type DataUploaderProps = DataUploaderPureProps & StateProps & DataUploaderDispatchProps;
const DataUploader: React.FC<DataUploaderProps> = (props) => {
// componentDidMount(): void {
// loadTransform(this.props);
// }
// private onAnalyzeButtonClick = (filter: string = DefaultFilter, sampleSize: string = this.state.sampleSize) => {
// const query = {
// command: "listSchema",
// database: this.props.databaseId,
// collection: this.props.collectionId,
// outputType: this.state.outputType,
// filter,
// sampleSize,
// };
// this.setState({
// isFiltering: true,
// });
// this.props.updateCell(JSON.stringify(query), this.props.firstCellId, this.props.contentRef);
// this.clickAnalyzeTelemetryStartKey = traceStart(Action.DataUploaderClickAnalyze, {
// database: this.props.databaseId,
// collection: this.props.collectionId,
// sampleSize,
// });
// this.props.runCell(this.props.contentRef, this.props.firstCellId);
// };
const { firstCellId: id, contentRef, kernelStatus } = props;
// eslint-disable-next-line no-console
console.log("firstCellId: id, contentRef, kernelStatus", id, contentRef, kernelStatus);
const isKernelBusy = kernelStatus === "busy";
const isKernelIdle = kernelStatus === "idle";
const baseStyle: CSSProperties = {
display: "flex",
flexDirection: "column",
alignItems: "center",
padding: "20px",
borderWidth: 2,
borderRadius: 2,
borderColor: "#eeeeee",
borderStyle: "dashed",
backgroundColor: "#fafafa",
color: "#bdbdbd",
transition: "border .3s ease-in-out",
};
const activeStyle = {
borderColor: "#2196f3",
};
const acceptStyle = {
borderColor: "#00e676",
};
const rejectStyle = {
borderColor: "#ff1744",
};
const onDrop = useCallback((acceptedFiles) => {
//eslint-disable-next-line no-console
console.log("acceptedFiles", acceptedFiles);
}, []);
const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
onDrop,
accept: ".json",
});
const style = useMemo(
() => ({
...baseStyle,
...(isDragActive ? activeStyle : {}),
...(isDragAccept ? acceptStyle : {}),
...(isDragReject ? rejectStyle : {}),
}),
[isDragActive, isDragReject, isDragAccept]
);
if (!id) {
return <></>;
}
return (
<div {...getRootProps({ style })}>
<input {...getInputProps()} />
<div>Drag and drop your json file here</div>
</div>
);
};
interface StateProps {
firstCellId: string;
kernelStatus: string;
outputs: Immutable.List<ImmutableOutput>;
}
interface InitialProps {
kernelRef: string;
contentRef: string;
}
// Redux
const makeMapStateToProps = (state: AppState, initialProps: InitialProps) => {
const { kernelRef, contentRef } = initialProps;
const mapStateToProps = (state: AppState) => {
let kernelStatus;
let firstCellId;
let outputs;
const kernel = selectors.kernel(state, { kernelRef });
if (kernel) {
kernelStatus = kernel.status;
}
const content = selectors.content(state, { contentRef });
if (content?.type === "notebook") {
const cellOrder = selectors.notebook.cellOrder(content.model);
if (cellOrder.size > 0) {
firstCellId = cellOrder.first() as string;
const model = selectors.model(state, { contentRef });
if (model && model.type === "notebook") {
const cell = selectors.notebook.cellById(model, { id: firstCellId });
if (cell) {
outputs = cell.get("outputs", Immutable.List());
}
}
}
}
return {
firstCellId,
kernelStatus,
outputs,
};
};
return mapStateToProps;
};
const makeMapDispatchToProps = () => {
const mapDispatchToProps = (dispatch: Dispatch) => {
return {
addTransform: (transform: React.ComponentType & { MIMETYPE: string }) => {
return dispatch(
actions.addTransform({
mediaType: transform.MIMETYPE,
component: transform,
})
);
},
runCell: (contentRef: ContentRef, cellId: string) => {
return dispatch(
actions.executeCell({
contentRef,
id: cellId,
})
);
},
updateCell: (text: string, id: string, contentRef: ContentRef) => {
dispatch(actions.updateCellSource({ id, contentRef, value: text }));
},
};
};
return mapDispatchToProps;
};
export default connect(makeMapStateToProps, makeMapDispatchToProps)(DataUploader);

View File

@@ -1,48 +0,0 @@
import { actions, createContentRef, createKernelRef, KernelRef } from "@nteract/core";
import DataUploader from "Explorer/Notebook/DataUploader/DataUploader";
import * as React from "react";
import { Provider } from "react-redux";
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
import {
NotebookComponentBootstrapper,
NotebookComponentBootstrapperOptions,
} from "../NotebookComponent/NotebookComponentBootstrapper";
import { DataUploaderNotebook } from "./DataUploaderUtils";
export class DataUploaderAdapter extends NotebookComponentBootstrapper implements ReactAdapter {
public parameters: unknown;
private kernelRef: KernelRef;
constructor(options: NotebookComponentBootstrapperOptions, private databaseId: string, private collectionId: string) {
super(options);
if (!this.contentRef) {
this.contentRef = createContentRef();
this.kernelRef = createKernelRef();
this.getStore().dispatch(
actions.fetchContent({
filepath: DataUploaderNotebook.path,
params: {},
kernelRef: this.kernelRef,
contentRef: this.contentRef,
})
);
}
}
public renderComponent(): JSX.Element {
const props = {
contentRef: this.contentRef,
kernelRef: this.kernelRef,
databaseId: this.databaseId,
collectionId: this.collectionId,
};
return (
<Provider store={this.getStore()}>
<DataUploader {...props} />;
</Provider>
);
}
}

View File

@@ -1,44 +0,0 @@
import { Notebook } from "@nteract/commutable";
import { IContent } from "@nteract/types";
import * as InMemoryContentProviderUtils from "../NotebookComponent/ContentProviders/InMemoryContentProviderUtils";
const notebookName = "data-uploader-component-notebook.ipynb";
const notebookPath = InMemoryContentProviderUtils.toContentUri(notebookName);
const notebook: Notebook = {
cells: [
{
cell_type: "code",
metadata: {},
execution_count: 0,
outputs: [],
source: "",
},
],
metadata: {
kernelspec: {
displayName: "Mongo",
language: "mongocli",
name: "mongo",
},
language_info: {
file_extension: "ipynb",
mimetype: "application/json",
name: "mongo",
version: "1.0",
},
},
nbformat: 4,
nbformat_minor: 4,
};
export const DataUploaderNotebook: IContent<"notebook"> = {
name: notebookName,
path: notebookPath,
type: "notebook",
writable: true,
created: "",
last_modified: "",
mimetype: "application/x-ipynb+json",
content: notebook,
format: "json",
};

View File

@@ -4,7 +4,6 @@
import { ImmutableNotebook } from "@nteract/commutable";
import type { IContentProvider } from "@nteract/core";
import { DataUploaderNotebook } from "Explorer/Notebook/DataUploader/DataUploaderUtils";
import React from "react";
import { contents } from "rx-jupyter";
import { Areas, HttpStatusCodes } from "../../Common/Constants";
@@ -69,10 +68,6 @@ export default class NotebookManager {
readonly: true,
content: SchemaAnalyzerNotebook,
},
[DataUploaderNotebook.path]: {
readonly: true,
content: DataUploaderNotebook,
},
});
this.gitHubContentProvider = new GitHubContentProvider({

View File

@@ -26,7 +26,6 @@ describe("OpenActions", () => {
collection.onDocumentDBDocumentsClick = jest.fn();
collection.onMongoDBDocumentsClick = jest.fn();
collection.onSchemaAnalyzerClick = jest.fn();
collection.onDataUploaderClick = jest.fn();
collection.onTableEntitiesClick = jest.fn();
collection.onGraphDocumentsClick = jest.fn();
collection.onNewQueryClick = jest.fn();

View File

@@ -86,14 +86,6 @@ function openCollectionTab(
break;
}
if (
action.tabKind === ActionContracts.TabKind.DataUploader ||
action.tabKind === ActionContracts.TabKind[ActionContracts.TabKind.DataUploader]
) {
collection.onDataUploaderClick();
break;
}
if (
action.tabKind === ActionContracts.TabKind.TableEntities ||
action.tabKind === ActionContracts.TabKind[ActionContracts.TabKind.TableEntities]

View File

@@ -1,41 +0,0 @@
import * as Constants from "../../Common/Constants";
import { Action } from "../../Shared/Telemetry/TelemetryConstants";
import { traceSuccess } from "../../Shared/Telemetry/TelemetryProcessor";
import { DataUploaderAdapter } from "../Notebook/DataUploader/DataUploaderAdapter";
import NotebookTabBase, { NotebookTabBaseOptions } from "./NotebookTabBase";
export default class DataUploaderTab extends NotebookTabBase {
public readonly html = '<div data-bind="react:DataUploaderAdapter" style="height: 100%"></div>';
private DataUploaderAdapter: DataUploaderAdapter;
constructor(options: NotebookTabBaseOptions) {
super(options);
this.DataUploaderAdapter = new DataUploaderAdapter(
{
contentRef: undefined,
notebookClient: NotebookTabBase.clientManager,
},
options.collection?.databaseId,
options.collection?.id()
);
}
public onActivate(): void {
traceSuccess(
Action.Tab,
{
databaseName: this.collection?.databaseId,
collectionName: this.collection?.id,
dataExplorerArea: Constants.Areas.Tab,
tabTitle: "Upload",
},
this.onLoadStartKey
);
super.onActivate();
}
protected buildCommandBarOptions(): void {
this.updateNavbarWithTabsButtons();
}
}

View File

@@ -308,7 +308,7 @@ export default class Collection implements ViewModels.Collection {
collectionName: this.id(),
dataExplorerArea: Constants.Areas.Tab,
tabTitle: "Items",
tabTitle: this.rawDataModel.id + " - Items",
});
this.documentIds([]);
@@ -316,7 +316,7 @@ export default class Collection implements ViewModels.Collection {
partitionKey: this.partitionKey,
documentIds: ko.observableArray<DocumentId>([]),
tabKind: ViewModels.CollectionTabKind.Documents,
title: "Items",
title: this.rawDataModel.id + " - Items",
collection: this,
node: this,
tabPath: `${this.databaseId}>${this.id()}>Documents`,
@@ -574,52 +574,6 @@ export default class Collection implements ViewModels.Collection {
);
};
public onDataUploaderClick = async () => {
if (useNotebook.getState().isPhoenixFeatures) {
await this.container.allocateContainer();
}
useSelectedNode.getState().setSelectedNode(this);
this.selectedSubnodeKind(ViewModels.CollectionTabKind.SchemaAnalyzer);
const DataUploaderTab = await (await import("../Tabs/DataUploaderTab")).default;
TelemetryProcessor.trace(Action.SelectItem, ActionModifiers.Mark, {
description: "Data uploader node",
databaseName: this.databaseId,
collectionName: this.id(),
dataExplorerArea: Constants.Areas.ResourceTree,
});
for (const tab of useTabs.getState().openedTabs) {
if (
tab instanceof DataUploaderTab &&
tab.collection?.databaseId === this.databaseId &&
tab.collection?.id() === this.id()
) {
return useTabs.getState().activateTab(tab);
}
}
const startKey = TelemetryProcessor.traceStart(Action.Tab, {
databaseName: this.databaseId,
collectionName: this.id(),
dataExplorerArea: Constants.Areas.Tab,
tabTitle: "Upload",
});
this.documentIds([]);
useTabs.getState().activateNewTab(
new DataUploaderTab({
account: userContext.databaseAccount,
masterKey: userContext.masterKey || "",
container: this.container,
tabKind: ViewModels.CollectionTabKind.DataUploader,
title: "Upload",
tabPath: "",
collection: this,
node: this,
onLoadStartKey: startKey,
})
);
};
public onSettingsClick = async (): Promise<void> => {
useSelectedNode.getState().setSelectedNode(this);
const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit;

View File

@@ -526,15 +526,6 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
.getState()
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.SchemaAnalyzer]),
});
children.push({
label: "Data Upload (Preview)",
onClick: collection.onDataUploaderClick.bind(collection),
isSelected: () =>
useSelectedNode
.getState()
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.DataUploader]),
});
}
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {

View File

@@ -283,15 +283,6 @@ export class ResourceTreeAdapter implements ReactAdapter {
.getState()
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.SchemaAnalyzer]),
});
children.push({
label: "Data Upload (Preview)",
onClick: collection.onDataUploaderClick.bind(collection),
isSelected: () =>
useSelectedNode
.getState()
.isDataNodeSelected(collection.databaseId, collection.id(), [ViewModels.CollectionTabKind.DataUploader]),
});
}
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {

View File

@@ -2,26 +2,28 @@ import { isInvalidParentFrameOrigin, isReadyMessage } from "./MessageValidation"
describe("isInvalidParentFrameOrigin", () => {
test.each`
domain | expected
${"https://cosmos.azure.com"} | ${false}
${"https://cosmos.azure.us"} | ${false}
${"https://cosmos.azure.cn"} | ${false}
${"https://portal.azure.com"} | ${false}
${"https://portal.azure.us"} | ${false}
${"https://portal.azure.cn"} | ${false}
${"https://portal.microsoftazure.de"} | ${false}
${"https://subdomain.portal.azure.com"} | ${false}
${"https://subdomain.portal.azure.us"} | ${false}
${"https://subdomain.portal.azure.cn"} | ${false}
${"https://main.documentdb.ext.azure.com"} | ${false}
${"https://main.documentdb.ext.azure.us"} | ${false}
${"https://main.documentdb.ext.azure.cn"} | ${false}
${"https://main.documentdb.ext.microsoftazure.de"} | ${false}
${"https://random.domain"} | ${true}
${"https://malicious.cloudapp.azure.com"} | ${true}
${"https://malicious.germanycentral.cloudapp.microsoftazure.de"} | ${true}
${"https://maliciousazure.com"} | ${true}
${"https://maliciousportalsazure.com"} | ${true}
domain | expected
${"https://cosmos.azure.com"} | ${false}
${"https://cosmos.azure.us"} | ${false}
${"https://cosmos.azure.cn"} | ${false}
${"https://portal.azure.com"} | ${false}
${"https://portal.azure.us"} | ${false}
${"https://portal.azure.cn"} | ${false}
${"https://portal.microsoftazure.de"} | ${false}
${"https://subdomain.portal.azure.com"} | ${false}
${"https://subdomain.portal.azure.us"} | ${false}
${"https://subdomain.portal.azure.cn"} | ${false}
${"https://main.documentdb.ext.azure.com"} | ${false}
${"https://main.documentdb.ext.azure.us"} | ${false}
${"https://main.documentdb.ext.azure.cn"} | ${false}
${"https://cosmos-db-dataexplorer-germanycentral.azurewebsites.de"} | ${false}
${"https://main.documentdb.ext.microsoftazure.de"} | ${false}
${"https://random.domain"} | ${true}
${"https://malicious.cloudapp.azure.com"} | ${true}
${"https://malicious.germanycentral.cloudapp.microsoftazure.de"} | ${true}
${"https://maliciousazure.com"} | ${true}
${"https://maliciousportalsazure.com"} | ${true}
${"https://cosmos-db-dataexplorer-germanycentralAazurewebsites.de"} | ${true}
`("returns $expected when called with $domain", ({ domain, expected }) => {
expect(isInvalidParentFrameOrigin({ origin: domain } as MessageEvent)).toBe(expected);
});