mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-30 15:14:19 +00:00
Compare commits
4 Commits
jbunster/t
...
cleanup/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b8ed7a555 | ||
|
|
c2923768f8 | ||
|
|
101ddbec17 | ||
|
|
b8ed534c90 |
@@ -119,10 +119,14 @@ src/Explorer/Panes/ContextualPaneBase.ts
|
|||||||
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
|
src/Explorer/Panes/DeleteDatabaseConfirmationPane.test.ts
|
||||||
src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts
|
src/Explorer/Panes/DeleteDatabaseConfirmationPane.ts
|
||||||
src/Explorer/Panes/GraphStylingPane.ts
|
src/Explorer/Panes/GraphStylingPane.ts
|
||||||
|
# src/Explorer/Panes/NewVertexPane.ts
|
||||||
src/Explorer/Panes/PaneComponents.ts
|
src/Explorer/Panes/PaneComponents.ts
|
||||||
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
src/Explorer/Panes/RenewAdHocAccessPane.ts
|
||||||
src/Explorer/Panes/SetupNotebooksPane.ts
|
src/Explorer/Panes/SetupNotebooksPane.ts
|
||||||
src/Explorer/Panes/SwitchDirectoryPane.ts
|
src/Explorer/Panes/SwitchDirectoryPane.ts
|
||||||
|
src/Explorer/Panes/Tables/EditTableEntityPane.ts
|
||||||
|
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
|
||||||
|
src/Explorer/Panes/Tables/TableEntityPane.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyNameValidator.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyValidationCommon.ts
|
||||||
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
|
src/Explorer/Panes/Tables/Validators/EntityPropertyValueValidator.ts
|
||||||
|
|||||||
@@ -188,3 +188,7 @@ Cosmos Explorer has been under constant development for over 5 years. As a resul
|
|||||||
✅ DO
|
✅ DO
|
||||||
|
|
||||||
- Support all [browsers supported by the Azure Portal](https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-supported-browsers-devices)
|
- Support all [browsers supported by the Azure Portal](https://docs.microsoft.com/en-us/azure/azure-portal/azure-portal-supported-browsers-devices)
|
||||||
|
- Support IE11
|
||||||
|
- In practice, this should not need to be considered as part of a normal development workflow
|
||||||
|
- Polyfills and transpilation are already provided by our engineering systems.
|
||||||
|
- This requirement will be removed on March 30th, 2021 when Azure drops IE11 support.
|
||||||
|
|||||||
3934
package-lock.json
generated
3934
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@@ -101,10 +101,10 @@
|
|||||||
"utility-types": "3.10.0"
|
"utility-types": "3.10.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.14.0",
|
"@babel/core": "7.9.0",
|
||||||
"@babel/preset-env": "7.14.1",
|
"@babel/preset-env": "7.9.0",
|
||||||
"@babel/preset-react": "7.13.13",
|
"@babel/preset-react": "7.9.4",
|
||||||
"@babel/preset-typescript": "7.13.0",
|
"@babel/preset-typescript": "7.9.0",
|
||||||
"@testing-library/react": "11.2.3",
|
"@testing-library/react": "11.2.3",
|
||||||
"@types/applicationinsights-js": "1.0.7",
|
"@types/applicationinsights-js": "1.0.7",
|
||||||
"@types/codemirror": "0.0.56",
|
"@types/codemirror": "0.0.56",
|
||||||
@@ -127,10 +127,10 @@
|
|||||||
"@types/sinon": "2.3.3",
|
"@types/sinon": "2.3.3",
|
||||||
"@types/styled-components": "5.1.1",
|
"@types/styled-components": "5.1.1",
|
||||||
"@types/underscore": "1.7.36",
|
"@types/underscore": "1.7.36",
|
||||||
"@typescript-eslint/eslint-plugin": "4.22.1",
|
"@typescript-eslint/eslint-plugin": "4.22.0",
|
||||||
"@typescript-eslint/parser": "4.22.1",
|
"@typescript-eslint/parser": "4.22.0",
|
||||||
"babel-jest": "26.6.3",
|
"babel-jest": "24.9.0",
|
||||||
"babel-loader": "8.2.2",
|
"babel-loader": "8.1.0",
|
||||||
"buffer": "5.1.0",
|
"buffer": "5.1.0",
|
||||||
"case-sensitive-paths-webpack-plugin": "2.3.0",
|
"case-sensitive-paths-webpack-plugin": "2.3.0",
|
||||||
"create-file-webpack": "1.0.2",
|
"create-file-webpack": "1.0.2",
|
||||||
@@ -138,7 +138,7 @@
|
|||||||
"enzyme": "3.11.0",
|
"enzyme": "3.11.0",
|
||||||
"enzyme-adapter-react-16": "1.15.5",
|
"enzyme-adapter-react-16": "1.15.5",
|
||||||
"enzyme-to-json": "3.6.1",
|
"enzyme-to-json": "3.6.1",
|
||||||
"eslint": "7.25.0",
|
"eslint": "7.8.1",
|
||||||
"eslint-cli": "1.1.1",
|
"eslint-cli": "1.1.1",
|
||||||
"eslint-plugin-no-null": "1.0.2",
|
"eslint-plugin-no-null": "1.0.2",
|
||||||
"eslint-plugin-prefer-arrow": "1.2.2",
|
"eslint-plugin-prefer-arrow": "1.2.2",
|
||||||
@@ -152,7 +152,7 @@
|
|||||||
"html-loader": "0.5.5",
|
"html-loader": "0.5.5",
|
||||||
"html-loader-jest": "0.2.1",
|
"html-loader-jest": "0.2.1",
|
||||||
"html-webpack-plugin": "4.5.2",
|
"html-webpack-plugin": "4.5.2",
|
||||||
"jest": "26.6.3",
|
"jest": "25.5.4",
|
||||||
"jest-canvas-mock": "2.1.0",
|
"jest-canvas-mock": "2.1.0",
|
||||||
"jest-playwright-preset": "1.5.1",
|
"jest-playwright-preset": "1.5.1",
|
||||||
"jest-trx-results-processor": "0.0.7",
|
"jest-trx-results-processor": "0.0.7",
|
||||||
@@ -169,10 +169,10 @@
|
|||||||
"rimraf": "3.0.0",
|
"rimraf": "3.0.0",
|
||||||
"sinon": "3.2.1",
|
"sinon": "3.2.1",
|
||||||
"style-loader": "0.23.0",
|
"style-loader": "0.23.0",
|
||||||
"ts-loader": "9.1.2",
|
"ts-loader": "6.2.2",
|
||||||
"tslint": "6.1.3",
|
"tslint": "5.11.0",
|
||||||
"tslint-microsoft-contrib": "6.2.0",
|
"tslint-microsoft-contrib": "6.0.0",
|
||||||
"typescript": "4.3.0-beta",
|
"typescript": "4.2.4",
|
||||||
"url-loader": "1.1.1",
|
"url-loader": "1.1.1",
|
||||||
"wait-on": "4.0.2",
|
"wait-on": "4.0.2",
|
||||||
"webpack": "4.46.0",
|
"webpack": "4.46.0",
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ export class ObjectCache<T> extends Map<string, T> {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override get(key: string): T | undefined {
|
public get(key: string): T | undefined {
|
||||||
return this.touch(key);
|
return this.touch(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override set(key: string, value: T): this {
|
public set(key: string, value: T): this {
|
||||||
if (this.size === this.limit) {
|
if (this.size === this.limit) {
|
||||||
this.delete(this.keys().next().value);
|
this.delete(this.keys().next().value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,4 +22,6 @@ ko.components.register("throughput-input-autopilot-v3", ThroughputInputComponent
|
|||||||
ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent());
|
ko.components.register("add-database-pane", new PaneComponents.AddDatabasePaneComponent());
|
||||||
ko.components.register("add-collection-pane", new PaneComponents.AddCollectionPaneComponent());
|
ko.components.register("add-collection-pane", new PaneComponents.AddCollectionPaneComponent());
|
||||||
ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent());
|
ko.components.register("graph-styling-pane", new PaneComponents.GraphStylingPaneComponent());
|
||||||
|
ko.components.register("table-add-entity-pane", new PaneComponents.TableAddEntityPaneComponent());
|
||||||
|
ko.components.register("table-edit-entity-pane", new PaneComponents.TableEditEntityPaneComponent());
|
||||||
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
ko.components.register("cassandra-add-collection-pane", new PaneComponents.CassandraAddCollectionPaneComponent());
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export class AccessibleElement extends React.Component<AccessibleElementProps> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const elementProps = { ...this.props };
|
const elementProps = { ...this.props };
|
||||||
delete elementProps.as;
|
delete elementProps.as;
|
||||||
delete elementProps.onActivated;
|
delete elementProps.onActivated;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import TriangleRightIcon from "../../../../images/Triangle-right.svg";
|
|||||||
export interface AccordionComponentProps {}
|
export interface AccordionComponentProps {}
|
||||||
|
|
||||||
export class AccordionComponent extends React.Component<AccordionComponentProps> {
|
export class AccordionComponent extends React.Component<AccordionComponentProps> {
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return <div className="accordion">{this.props.children}</div>;
|
return <div className="accordion">{this.props.children}</div>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ export class AccordionItemComponent extends React.Component<AccordionItemCompone
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
if (this.props.isExpanded !== this.isExpanded) {
|
if (this.props.isExpanded !== this.isExpanded) {
|
||||||
this.isExpanded = this.props.isExpanded;
|
this.isExpanded = this.props.isExpanded;
|
||||||
this.setState({
|
this.setState({
|
||||||
@@ -51,7 +51,7 @@ public override componentDidUpdate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="accordionItemContainer">
|
<div className="accordionItemContainer">
|
||||||
<div className="accordionItemHeader" onClick={this.onHeaderClick} onKeyPress={this.onHeaderKeyPress}>
|
<div className="accordionItemHeader" onClick={this.onHeaderClick} onKeyPress={this.onHeaderKeyPress}>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export class ArcadiaMenuPicker extends React.Component<ArcadiaMenuPickerProps, A
|
|||||||
this.props.onCreateNewSparkPoolClicked(item.key);
|
this.props.onCreateNewSparkPoolClicked(item.key);
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render() {
|
public render() {
|
||||||
const { workspaces } = this.props;
|
const { workspaces } = this.props;
|
||||||
let workspaceMenuItems: IContextualMenuItem[] = workspaces.map((workspace) => {
|
let workspaceMenuItems: IContextualMenuItem[] = workspaces.map((workspace) => {
|
||||||
let sparkPoolsMenuProps: IContextualMenuProps = {
|
let sparkPoolsMenuProps: IContextualMenuProps = {
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export interface CollapsiblePanelProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class CollapsiblePanel extends React.Component<CollapsiblePanelProps> {
|
export class CollapsiblePanel extends React.Component<CollapsiblePanelProps> {
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className={`collapsiblePanel ${this.props.isCollapsed ? "paneCollapsed" : ""}`}>
|
<div className={`collapsiblePanel ${this.props.isCollapsed ? "paneCollapsed" : ""}`}>
|
||||||
{!this.props.isCollapsed ? this.getExpandedFragment() : this.getCollapsedFragment()}
|
{!this.props.isCollapsed ? this.getExpandedFragment() : this.getCollapsedFragment()}
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
|
|||||||
this.setState({ isExpanded: !this.state.isExpanded });
|
this.setState({ isExpanded: !this.state.isExpanded });
|
||||||
};
|
};
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
public componentDidUpdate(): void {
|
||||||
if (this.state.isExpanded && this.props.onExpand) {
|
if (this.state.isExpanded && this.props.onExpand) {
|
||||||
this.props.onExpand();
|
this.props.onExpand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack
|
<Stack
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ export class CommandButtonComponent extends React.Component<CommandButtonCompone
|
|||||||
private dropdownElt: HTMLElement;
|
private dropdownElt: HTMLElement;
|
||||||
private expandButtonElt: HTMLElement;
|
private expandButtonElt: HTMLElement;
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
public componentDidUpdate(): void {
|
||||||
if (!this.dropdownElt || !this.expandButtonElt) {
|
if (!this.dropdownElt || !this.expandButtonElt) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -243,7 +243,7 @@ export class CommandButtonComponent extends React.Component<CommandButtonCompone
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
let mainClassName = "commandButtonComponent";
|
let mainClassName = "commandButtonComponent";
|
||||||
if (this.props.disabled) {
|
if (this.props.disabled) {
|
||||||
mainClassName += " commandDisabled";
|
mainClassName += " commandDisabled";
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export interface DefaultDirectoryDropdownProps {
|
|||||||
export class DefaultDirectoryDropdownComponent extends React.Component<DefaultDirectoryDropdownProps> {
|
export class DefaultDirectoryDropdownComponent extends React.Component<DefaultDirectoryDropdownProps> {
|
||||||
public static readonly lastVisitedKey: string = "lastVisited";
|
public static readonly lastVisitedKey: string = "lastVisited";
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const lastVisitedOption: IDropdownOption = {
|
const lastVisitedOption: IDropdownOption = {
|
||||||
key: DefaultDirectoryDropdownComponent.lastVisitedKey,
|
key: DefaultDirectoryDropdownComponent.lastVisitedKey,
|
||||||
text: "Sign in to your last visited directory",
|
text: "Sign in to your last visited directory",
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export class DirectoryListComponent extends React.Component<DirectoryListProps,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const { directories: originalItems, selectedDirectoryId } = this.props;
|
const { directories: originalItems, selectedDirectoryId } = this.props;
|
||||||
const { filterText } = this.state;
|
const { filterText } = this.state;
|
||||||
const filteredItems =
|
const filteredItems =
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export class DynamicListViewModel extends WaitsForTemplateViewModel {
|
|||||||
public ariaLabel: string;
|
public ariaLabel: string;
|
||||||
public buttonText: string;
|
public buttonText: string;
|
||||||
public newItem: ko.Observable<string>;
|
public newItem: ko.Observable<string>;
|
||||||
public override isTemplateReady: ko.Observable<boolean>;
|
public isTemplateReady: ko.Observable<boolean>;
|
||||||
public listItems: ko.ObservableArray<DynamicListItem>;
|
public listItems: ko.ObservableArray<DynamicListItem>;
|
||||||
|
|
||||||
public constructor(options: DynamicListParams) {
|
public constructor(options: DynamicListParams) {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export interface EditorParams extends JsonEditorParams {
|
|||||||
*/
|
*/
|
||||||
// TODO: Ideally, JsonEditorViewModel should extend EditorViewModel and not the other way around
|
// TODO: Ideally, JsonEditorViewModel should extend EditorViewModel and not the other way around
|
||||||
class EditorViewModel extends JsonEditorViewModel {
|
class EditorViewModel extends JsonEditorViewModel {
|
||||||
public override params: EditorParams;
|
public params: EditorParams;
|
||||||
private static providerRegistered: string[] = [];
|
private static providerRegistered: string[] = [];
|
||||||
|
|
||||||
public constructor(params: EditorParams) {
|
public constructor(params: EditorParams) {
|
||||||
@@ -44,11 +44,11 @@ class EditorViewModel extends JsonEditorViewModel {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override getEditorLanguage(): string {
|
protected getEditorLanguage(): string {
|
||||||
return this.params.contentType;
|
return this.params.contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async registerCompletionItemProvider() {
|
protected async registerCompletionItemProvider() {
|
||||||
if (EditorViewModel.providerRegistered.indexOf("sql") < 0) {
|
if (EditorViewModel.providerRegistered.indexOf("sql") < 0) {
|
||||||
const { SqlCompletionItemProvider } = await import("@azure/cosmos-language-service");
|
const { SqlCompletionItemProvider } = await import("@azure/cosmos-language-service");
|
||||||
const monaco = await loadMonaco();
|
const monaco = await loadMonaco();
|
||||||
@@ -57,7 +57,7 @@ class EditorViewModel extends JsonEditorViewModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async getErrorMarkers(input: string): Promise<monaco.editor.IMarkerData[]> {
|
protected async getErrorMarkers(input: string): Promise<monaco.editor.IMarkerData[]> {
|
||||||
const { ErrorMarkProvider } = await import("@azure/cosmos-language-service");
|
const { ErrorMarkProvider } = await import("@azure/cosmos-language-service");
|
||||||
return ErrorMarkProvider.getErrorMark(input);
|
return ErrorMarkProvider.getErrorMark(input);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,20 +21,20 @@ export class EditorReact extends React.Component<EditorReactProps> {
|
|||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
this.createEditor(this.configureEditor.bind(this));
|
this.createEditor(this.configureEditor.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override shouldComponentUpdate(): boolean {
|
public shouldComponentUpdate(): boolean {
|
||||||
// Prevents component re-rendering
|
// Prevents component re-rendering
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentWillUnmount(): void {
|
public componentWillUnmount(): void {
|
||||||
this.selectionListener && this.selectionListener.dispose();
|
this.selectionListener && this.selectionListener.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return <div className="jsonEditor" ref={(elt: HTMLElement) => this.setRef(elt)} />;
|
return <div className="jsonEditor" ref={(elt: HTMLElement) => this.setRef(elt)} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export class AddRepoComponent extends React.Component<AddRepoComponentProps, Add
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const textFieldProps: ITextFieldProps = {
|
const textFieldProps: ITextFieldProps = {
|
||||||
placeholder: AddRepoComponent.TextFieldPlaceholder,
|
placeholder: AddRepoComponent.TextFieldPlaceholder,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export class AuthorizeAccessComponent extends React.Component<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const choiceGroupProps: IChoiceGroupProps = {
|
const choiceGroupProps: IChoiceGroupProps = {
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export class GitHubReposComponent extends React.Component<GitHubReposComponentPr
|
|||||||
private static readonly OKButtonText = "OK";
|
private static readonly OKButtonText = "OK";
|
||||||
private static readonly CancelButtonText = "Cancel";
|
private static readonly CancelButtonText = "Cancel";
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const content: JSX.Element = this.props.showAuthorizeAccess ? (
|
const content: JSX.Element = this.props.showAuthorizeAccess ? (
|
||||||
<AuthorizeAccessComponent {...this.props.authorizeAccessProps} />
|
<AuthorizeAccessComponent {...this.props.authorizeAccessProps} />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ export class ReposListComponent extends React.Component<ReposListComponentProps>
|
|||||||
private static readonly DefaultBranchName = "master";
|
private static readonly DefaultBranchName = "master";
|
||||||
private static readonly FooterIndex = -1;
|
private static readonly FooterIndex = -1;
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const pinnedReposListProps: IDetailsListProps = {
|
const pinnedReposListProps: IDetailsListProps = {
|
||||||
styles: {
|
styles: {
|
||||||
contentWrapper: {
|
contentWrapper: {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export class GalleryHeaderComponent extends React.Component {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack
|
<Stack
|
||||||
tokens={{ childrenGap: 10 }}
|
tokens={{ childrenGap: 10 }}
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ export class InputTypeaheadComponent extends React.Component<
|
|||||||
* @param prevState
|
* @param prevState
|
||||||
* @param snapshot
|
* @param snapshot
|
||||||
*/
|
*/
|
||||||
public override componentDidUpdate(
|
public componentDidUpdate(
|
||||||
prevProps: InputTypeaheadComponentProps,
|
prevProps: InputTypeaheadComponentProps,
|
||||||
prevState: InputTypeaheadComponentState,
|
prevState: InputTypeaheadComponentState,
|
||||||
snapshot: any
|
snapshot: any
|
||||||
@@ -127,11 +127,11 @@ export class InputTypeaheadComponent extends React.Component<
|
|||||||
/**
|
/**
|
||||||
* Executed once react is done building the DOM for this component
|
* Executed once react is done building the DOM for this component
|
||||||
*/
|
*/
|
||||||
public override componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
this.initializeTypeahead();
|
this.initializeTypeahead();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<span className="input-typeahead-container">
|
<span className="input-typeahead-container">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
|
|||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="notebookTerminalContainer">
|
<div className="notebookTerminalContainer">
|
||||||
<iframe
|
<iframe
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export class GalleryAndNotebookViewerComponent extends React.Component<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
if (this.state.notebookUrl) {
|
if (this.state.notebookUrl) {
|
||||||
const props: NotebookViewerComponentProps = {
|
const props: NotebookViewerComponentProps = {
|
||||||
container: this.props.container,
|
container: this.props.container,
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ export class GalleryViewerComponent extends React.Component<GalleryViewerCompone
|
|||||||
this.loadFavoriteNotebooks(this.state.searchText, this.state.sortBy, false); // Need this to show correct favorite button state
|
this.loadFavoriteNotebooks(this.state.searchText, this.state.sortBy, false); // Need this to show correct favorite button state
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
this.traceViewGallery();
|
this.traceViewGallery();
|
||||||
|
|
||||||
const tabs: GalleryTabInfo[] = [
|
const tabs: GalleryTabInfo[] = [
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export class InfoComponent extends React.Component<InfoComponentProps> {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<HoverCard plainCardProps={{ onRenderPlainCard: this.onHover }} instantOpenOnClick type={HoverCardType.plain}>
|
<HoverCard plainCardProps={{ onRenderPlainCard: this.onHover }} instantOpenOnClick type={HoverCardType.plain}>
|
||||||
<div className="infoPanelMain">
|
<div className="infoPanelMain">
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export class NotebookMetadataComponent extends React.Component<NotebookMetadataC
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const options: Intl.DateTimeFormatOptions = {
|
const options: Intl.DateTimeFormatOptions = {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "short",
|
month: "short",
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export class NotebookViewerComponent
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="notebookViewerContainer">
|
<div className="notebookViewerContainer">
|
||||||
{this.props.backNavigationText !== undefined ? (
|
{this.props.backNavigationText !== undefined ? (
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ export class QueriesGridComponent extends React.Component<QueriesGridComponentPr
|
|||||||
this.selection.setItems(this.state.filteredResults);
|
this.selection.setItems(this.state.filteredResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(prevProps: QueriesGridComponentProps, prevState: QueriesGridComponentState): void {
|
public componentDidUpdate(prevProps: QueriesGridComponentProps, prevState: QueriesGridComponentState): void {
|
||||||
this.selection.setItems(
|
this.selection.setItems(
|
||||||
this.state.filteredResults,
|
this.state.filteredResults,
|
||||||
!_.isEqual(prevState.filteredResults, this.state.filteredResults)
|
!_.isEqual(prevState.filteredResults, this.state.filteredResults)
|
||||||
@@ -79,11 +79,11 @@ export class QueriesGridComponent extends React.Component<QueriesGridComponentPr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fetched saved queries when panel open
|
// fetched saved queries when panel open
|
||||||
public override componentDidMount() {
|
public componentDidMount() {
|
||||||
this.fetchSavedQueries();
|
this.fetchSavedQueries();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
if (this.state.queries.length === 0) {
|
if (this.state.queries.length === 0) {
|
||||||
return this.renderBannerComponent();
|
return this.renderBannerComponent();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export interface RadioSwitchComponentProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class RadioSwitchComponent extends React.Component<RadioSwitchComponentProps> {
|
export class RadioSwitchComponent extends React.Component<RadioSwitchComponentProps> {
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="radioSwitchComponent">
|
<div className="radioSwitchComponent">
|
||||||
{this.props.choices.map((choice: Choice) => (
|
{this.props.choices.map((choice: Choice) => (
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export abstract class ResizeSensorComponent<P, S> extends React.Component<P, S>
|
|||||||
protected abstract onDimensionsChanged(width: number, height: number): void;
|
protected abstract onDimensionsChanged(width: number, height: number): void;
|
||||||
protected abstract getSensorTarget(): HTMLElement;
|
protected abstract getSensorTarget(): HTMLElement;
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
public componentDidUpdate(): void {
|
||||||
if (this.isSensing) {
|
if (this.isSensing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ export abstract class ResizeSensorComponent<P, S> extends React.Component<P, S>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentWillUnmount(): void {
|
public componentWillUnmount(): void {
|
||||||
if (!!this.resizeSensor) {
|
if (!!this.resizeSensor) {
|
||||||
this.resizeSensor.detach();
|
this.resizeSensor.detach();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
if (this.isCollectionSettingsTab) {
|
if (this.isCollectionSettingsTab) {
|
||||||
this.refreshIndexTransformationProgress();
|
this.refreshIndexTransformationProgress();
|
||||||
this.loadMongoIndexes();
|
this.loadMongoIndexes();
|
||||||
@@ -226,7 +226,7 @@ public override componentDidMount(): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
componentDidUpdate(): void {
|
||||||
if (this.props.settingsTab.isActive()) {
|
if (this.props.settingsTab.isActive()) {
|
||||||
this.props.settingsTab.getContainer().onUpdateTabsButtons(this.getTabsButtons());
|
this.props.settingsTab.getContainer().onUpdateTabsButtons(this.getTabsButtons());
|
||||||
}
|
}
|
||||||
@@ -879,7 +879,7 @@ public override componentDidUpdate(): void {
|
|||||||
return mongoIndexingPolicyAADError;
|
return mongoIndexingPolicyAADError;
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const scaleComponentProps: ScaleComponentProps = {
|
const scaleComponentProps: ScaleComponentProps = {
|
||||||
collection: this.collection,
|
collection: this.collection,
|
||||||
database: this.database,
|
database: this.database,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
} from "./SettingsRenderUtils";
|
} from "./SettingsRenderUtils";
|
||||||
|
|
||||||
class SettingsRenderUtilsTestComponent extends React.Component {
|
class SettingsRenderUtilsTestComponent extends React.Component {
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const estimatedSpendingColumns: IColumn[] = [
|
const estimatedSpendingColumns: IColumn[] = [
|
||||||
{ key: "costType", name: "", fieldName: "costType", minWidth: 100, maxWidth: 200, isResizable: true },
|
{ key: "costType", name: "", fieldName: "costType", minWidth: 100, maxWidth: 200, isResizable: true },
|
||||||
{ key: "hourly", name: "Hourly", fieldName: "hourly", minWidth: 100, maxWidth: 200, isResizable: true },
|
{ key: "hourly", name: "Hourly", fieldName: "hourly", minWidth: 100, maxWidth: 200, isResizable: true },
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ export class ConflictResolutionComponent extends React.Component<ConflictResolut
|
|||||||
{ key: DataModels.ConflictResolutionMode.Custom, text: "Merge Procedure (custom)" },
|
{ key: DataModels.ConflictResolutionMode.Custom, text: "Merge Procedure (custom)" },
|
||||||
];
|
];
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
componentDidUpdate(): void {
|
||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ public override componentDidUpdate(): void {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack {...subComponentStackProps}>
|
<Stack {...subComponentStackProps}>
|
||||||
{this.getConflictResolutionModeComponent()}
|
{this.getConflictResolutionModeComponent()}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export class IndexingPolicyComponent extends React.Component<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
componentDidUpdate(): void {
|
||||||
if (this.props.shouldDiscardIndexingPolicy) {
|
if (this.props.shouldDiscardIndexingPolicy) {
|
||||||
this.resetIndexingPolicyEditor();
|
this.resetIndexingPolicyEditor();
|
||||||
this.props.resetShouldDiscardIndexingPolicy();
|
this.props.resetShouldDiscardIndexingPolicy();
|
||||||
@@ -46,7 +46,7 @@ public override componentDidUpdate(): void {
|
|||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
this.resetIndexingPolicyEditor();
|
this.resetIndexingPolicyEditor();
|
||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ public override componentDidMount(): void {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack {...titleAndInputStackProps}>
|
<Stack {...titleAndInputStackProps}>
|
||||||
<IndexingPolicyRefreshComponent
|
<IndexingPolicyRefreshComponent
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export class IndexingPolicyRefreshComponent extends React.Component<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return this.renderIndexTransformationWarning() ? (
|
return this.renderIndexTransformationWarning() ? (
|
||||||
<MessageBar messageBarType={MessageBarType.warning}>{this.renderIndexTransformationWarning()}</MessageBar>
|
<MessageBar messageBarType={MessageBarType.warning}>{this.renderIndexTransformationWarning()}</MessageBar>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export class AddMongoIndexComponent extends React.Component<AddMongoIndexCompone
|
|||||||
this.descriptionTextField.focus();
|
this.descriptionTextField.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack {...mongoWarningStackProps}>
|
<Stack {...mongoWarningStackProps}>
|
||||||
<Stack horizontal tokens={addMongoIndexSubElementsTokens}>
|
<Stack horizontal tokens={addMongoIndexSubElementsTokens}>
|
||||||
|
|||||||
@@ -89,14 +89,14 @@ export class MongoIndexingPolicyComponent extends React.Component<MongoIndexingP
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
public override componentDidUpdate(prevProps: MongoIndexingPolicyComponentProps): void {
|
componentDidUpdate(prevProps: MongoIndexingPolicyComponentProps): void {
|
||||||
if (this.props.indexesToAdd.length > prevProps.indexesToAdd.length) {
|
if (this.props.indexesToAdd.length > prevProps.indexesToAdd.length) {
|
||||||
this.addMongoIndexComponentRefs[prevProps.indexesToAdd.length]?.current?.focus();
|
this.addMongoIndexComponentRefs[prevProps.indexesToAdd.length]?.current?.focus();
|
||||||
}
|
}
|
||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,7 +311,7 @@ public override componentDidMount(): void {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
if (this.props.mongoIndexes) {
|
if (this.props.mongoIndexes) {
|
||||||
if (this.hasCompoundIndex()) {
|
if (this.hasCompoundIndex()) {
|
||||||
return mongoCompoundIndexNotSupportedMessage;
|
return mongoCompoundIndexNotSupportedMessage;
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ export class ScaleComponent extends React.Component<ScaleComponentProps> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack {...subComponentStackProps}>
|
<Stack {...subComponentStackProps}>
|
||||||
{this.isFreeTierAccount() && (
|
{this.isFreeTierAccount() && (
|
||||||
|
|||||||
@@ -72,11 +72,11 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
|
|||||||
this.partitionKeyName = userContext.apiType === "Mongo" ? "Shard key" : "Partition key";
|
this.partitionKeyName = userContext.apiType === "Mongo" ? "Shard key" : "Partition key";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
componentDidUpdate(): void {
|
||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ public override componentDidUpdate(): void {
|
|||||||
|
|
||||||
public isLargePartitionKeyEnabled = (): boolean => this.props.collection.partitionKey?.version >= 2;
|
public isLargePartitionKeyEnabled = (): boolean => this.props.collection.partitionKey?.version >= 2;
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack {...subComponentStackProps}>
|
<Stack {...subComponentStackProps}>
|
||||||
{userContext.apiType !== "Cassandra" && this.getTtlComponent()}
|
{userContext.apiType !== "Cassandra" && this.getTtlComponent()}
|
||||||
|
|||||||
@@ -96,11 +96,11 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
|
|||||||
{ key: "false", text: "Manual" },
|
{ key: "false", text: "Manual" },
|
||||||
];
|
];
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
componentDidUpdate(): void {
|
||||||
this.onComponentUpdate();
|
this.onComponentUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -627,7 +627,7 @@ public override componentDidUpdate(): void {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Stack {...checkBoxAndInputStackProps}>
|
<Stack {...checkBoxAndInputStackProps}>
|
||||||
{this.renderWarningMessage()}
|
{this.renderWarningMessage()}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export interface ToolTipLabelComponentProps {
|
|||||||
const iconButtonStyles: Partial<IIconStyles> = { root: { marginBottom: -3 } };
|
const iconButtonStyles: Partial<IIconStyles> = { root: { marginBottom: -3 } };
|
||||||
|
|
||||||
export class ToolTipLabelComponent extends React.Component<ToolTipLabelComponentProps> {
|
export class ToolTipLabelComponent extends React.Component<ToolTipLabelComponentProps> {
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Stack horizontal verticalAlign="center" tokens={toolTipLabelStackTokens}>
|
<Stack horizontal verticalAlign="center" tokens={toolTipLabelStackTokens}>
|
||||||
|
|||||||
@@ -103,7 +103,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -224,7 +223,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionPane": AddCollectionPane {
|
"addCollectionPane": AddCollectionPane {
|
||||||
"_isSynapseLinkEnabled": [Function],
|
"_isSynapseLinkEnabled": [Function],
|
||||||
@@ -254,7 +252,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -1226,7 +1223,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isServerlessEnabled": [Function],
|
"isServerlessEnabled": [Function],
|
||||||
"isSparkEnabled": [Function],
|
"isSparkEnabled": [Function],
|
||||||
"isSparkEnabledForAccount": [Function],
|
"isSparkEnabledForAccount": undefined,
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"junoClient": JunoClient {
|
"junoClient": JunoClient {
|
||||||
@@ -1245,6 +1242,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
|
"refreshSparkEnabledStateForAccount": undefined,
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
"resourceTokenCollection": [Function],
|
"resourceTokenCollection": [Function],
|
||||||
"resourceTokenCollectionId": [Function],
|
"resourceTokenCollectionId": [Function],
|
||||||
@@ -1381,7 +1379,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -1502,7 +1499,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionPane": AddCollectionPane {
|
"addCollectionPane": AddCollectionPane {
|
||||||
"_isSynapseLinkEnabled": [Function],
|
"_isSynapseLinkEnabled": [Function],
|
||||||
@@ -1532,7 +1528,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -2504,7 +2499,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isServerlessEnabled": [Function],
|
"isServerlessEnabled": [Function],
|
||||||
"isSparkEnabled": [Function],
|
"isSparkEnabled": [Function],
|
||||||
"isSparkEnabledForAccount": [Function],
|
"isSparkEnabledForAccount": undefined,
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"junoClient": JunoClient {
|
"junoClient": JunoClient {
|
||||||
@@ -2523,6 +2518,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
|
"refreshSparkEnabledStateForAccount": undefined,
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
"resourceTokenCollection": [Function],
|
"resourceTokenCollection": [Function],
|
||||||
"resourceTokenCollectionId": [Function],
|
"resourceTokenCollectionId": [Function],
|
||||||
@@ -2672,7 +2668,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -2793,7 +2788,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionPane": AddCollectionPane {
|
"addCollectionPane": AddCollectionPane {
|
||||||
"_isSynapseLinkEnabled": [Function],
|
"_isSynapseLinkEnabled": [Function],
|
||||||
@@ -2823,7 +2817,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -3795,7 +3788,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isServerlessEnabled": [Function],
|
"isServerlessEnabled": [Function],
|
||||||
"isSparkEnabled": [Function],
|
"isSparkEnabled": [Function],
|
||||||
"isSparkEnabledForAccount": [Function],
|
"isSparkEnabledForAccount": undefined,
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"junoClient": JunoClient {
|
"junoClient": JunoClient {
|
||||||
@@ -3814,6 +3807,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
|
"refreshSparkEnabledStateForAccount": undefined,
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
"resourceTokenCollection": [Function],
|
"resourceTokenCollection": [Function],
|
||||||
"resourceTokenCollectionId": [Function],
|
"resourceTokenCollectionId": [Function],
|
||||||
@@ -3950,7 +3944,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -4071,7 +4064,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionPane": AddCollectionPane {
|
"addCollectionPane": AddCollectionPane {
|
||||||
"_isSynapseLinkEnabled": [Function],
|
"_isSynapseLinkEnabled": [Function],
|
||||||
@@ -4101,7 +4093,6 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -5073,7 +5064,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isServerlessEnabled": [Function],
|
"isServerlessEnabled": [Function],
|
||||||
"isSparkEnabled": [Function],
|
"isSparkEnabled": [Function],
|
||||||
"isSparkEnabledForAccount": [Function],
|
"isSparkEnabledForAccount": undefined,
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"junoClient": JunoClient {
|
"junoClient": JunoClient {
|
||||||
@@ -5092,6 +5083,7 @@ exports[`SettingsComponent renders 1`] = `
|
|||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
|
"refreshSparkEnabledStateForAccount": undefined,
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
"resourceTokenCollection": [Function],
|
"resourceTokenCollection": [Function],
|
||||||
"resourceTokenCollectionId": [Function],
|
"resourceTokenCollectionId": [Function],
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
};
|
};
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
componentDidUpdate(): void {
|
||||||
if (!this.shouldCheckErrors) {
|
if (!this.shouldCheckErrors) {
|
||||||
this.shouldCheckErrors = true;
|
this.shouldCheckErrors = true;
|
||||||
return;
|
return;
|
||||||
@@ -407,7 +407,7 @@ public override componentDidUpdate(): void {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
return this.renderNode(this.props.descriptor.root);
|
return this.renderNode(this.props.descriptor.root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export class TabComponent extends React.Component<TabComponentProps> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const currentTabContent = this.props.tabs[this.props.currentTabIndex].content;
|
const currentTabContent = this.props.tabs[this.props.currentTabIndex].content;
|
||||||
let className = "tabComponentContent";
|
let className = "tabComponentContent";
|
||||||
if (currentTabContent.className) {
|
if (currentTabContent.className) {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export class ThroughputInput extends React.Component<ThroughputInputProps, Throu
|
|||||||
this.props.setIsAutoscale(true);
|
this.props.setIsAutoscale(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="throughputInputContainer throughputInputSpacing">
|
<div className="throughputInputContainer throughputInputSpacing">
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export interface TreeComponentProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class TreeComponent extends React.Component<TreeComponentProps> {
|
export class TreeComponent extends React.Component<TreeComponentProps> {
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div style={this.props.style} className={`treeComponent ${this.props.className}`}>
|
<div style={this.props.style} className={`treeComponent ${this.props.className}`}>
|
||||||
<TreeNodeComponent paddingLeft={0} node={this.props.rootNode} generation={0} />
|
<TreeNodeComponent paddingLeft={0} node={this.props.rootNode} generation={0} />
|
||||||
@@ -93,7 +93,7 @@ export class TreeNodeComponent extends React.Component<TreeNodeComponentProps, T
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(prevProps: TreeNodeComponentProps, prevState: TreeNodeComponentState) {
|
componentDidUpdate(prevProps: TreeNodeComponentProps, prevState: TreeNodeComponentState) {
|
||||||
// Only call when expand has actually changed
|
// Only call when expand has actually changed
|
||||||
if (this.state.isExpanded !== prevState.isExpanded) {
|
if (this.state.isExpanded !== prevState.isExpanded) {
|
||||||
if (this.state.isExpanded) {
|
if (this.state.isExpanded) {
|
||||||
@@ -110,7 +110,7 @@ public override componentDidUpdate(prevProps: TreeNodeComponentProps, prevState:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return this.renderNode(this.props.node, this.props.generation);
|
return this.renderNode(this.props.node, this.props.generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { IChoiceGroupProps } from "@fluentui/react";
|
import { IChoiceGroupProps } from "@fluentui/react";
|
||||||
import * as ko from "knockout";
|
import * as ko from "knockout";
|
||||||
|
import * as path from "path";
|
||||||
import Q from "q";
|
import Q from "q";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import _ from "underscore";
|
import _ from "underscore";
|
||||||
@@ -96,6 +97,8 @@ export interface ExplorerParams {
|
|||||||
closeDialog: () => void;
|
closeDialog: () => void;
|
||||||
openDialog: (props: DialogProps) => void;
|
openDialog: (props: DialogProps) => void;
|
||||||
tabsManager: TabsManager;
|
tabsManager: TabsManager;
|
||||||
|
refreshSparkEnabledStateForAccount: () => void;
|
||||||
|
isSparkEnabledForAccount: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Explorer {
|
export default class Explorer {
|
||||||
@@ -173,7 +176,6 @@ export default class Explorer {
|
|||||||
public notebookWorkspaceManager: NotebookWorkspaceManager;
|
public notebookWorkspaceManager: NotebookWorkspaceManager;
|
||||||
public sparkClusterConnectionInfo: ko.Observable<DataModels.SparkClusterConnectionInfo>;
|
public sparkClusterConnectionInfo: ko.Observable<DataModels.SparkClusterConnectionInfo>;
|
||||||
public isSparkEnabled: ko.Observable<boolean>;
|
public isSparkEnabled: ko.Observable<boolean>;
|
||||||
public isSparkEnabledForAccount: ko.Observable<boolean>;
|
|
||||||
public arcadiaToken: ko.Observable<string>;
|
public arcadiaToken: ko.Observable<string>;
|
||||||
public arcadiaWorkspaces: ko.ObservableArray<ArcadiaWorkspaceItem>;
|
public arcadiaWorkspaces: ko.ObservableArray<ArcadiaWorkspaceItem>;
|
||||||
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
public hasStorageAnalyticsAfecFeature: ko.Observable<boolean>;
|
||||||
@@ -192,6 +194,10 @@ export default class Explorer {
|
|||||||
content: string;
|
content: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Refresh spark
|
||||||
|
public refreshSparkEnabledStateForAccount: () => void;
|
||||||
|
public isSparkEnabledForAccount: boolean;
|
||||||
|
|
||||||
// React adapters
|
// React adapters
|
||||||
private commandBarComponentAdapter: CommandBarComponentAdapter;
|
private commandBarComponentAdapter: CommandBarComponentAdapter;
|
||||||
|
|
||||||
@@ -207,6 +213,8 @@ export default class Explorer {
|
|||||||
this.closeSidePanel = params?.closeSidePanel;
|
this.closeSidePanel = params?.closeSidePanel;
|
||||||
this.closeDialog = params?.closeDialog;
|
this.closeDialog = params?.closeDialog;
|
||||||
this.openDialog = params?.openDialog;
|
this.openDialog = params?.openDialog;
|
||||||
|
this.refreshSparkEnabledStateForAccount = params?.refreshSparkEnabledStateForAccount;
|
||||||
|
this.isSparkEnabledForAccount = params?.isSparkEnabledForAccount;
|
||||||
|
|
||||||
const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, {
|
const startKey: number = TelemetryProcessor.traceStart(Action.InitializeDataExplorer, {
|
||||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
dataExplorerArea: Constants.Areas.ResourceTree,
|
||||||
@@ -232,8 +240,7 @@ export default class Explorer {
|
|||||||
});
|
});
|
||||||
this.isNotebooksEnabledForAccount = ko.observable(false);
|
this.isNotebooksEnabledForAccount = ko.observable(false);
|
||||||
this.isNotebooksEnabledForAccount.subscribe((isEnabledForAccount: boolean) => this.refreshCommandBarButtons());
|
this.isNotebooksEnabledForAccount.subscribe((isEnabledForAccount: boolean) => this.refreshCommandBarButtons());
|
||||||
this.isSparkEnabledForAccount = ko.observable(false);
|
// this.isSparkEnabledForAccount.subscribe((isEnabledForAccount: boolean) => this.refreshCommandBarButtons());
|
||||||
this.isSparkEnabledForAccount.subscribe((isEnabledForAccount: boolean) => this.refreshCommandBarButtons());
|
|
||||||
this.hasStorageAnalyticsAfecFeature = ko.observable(false);
|
this.hasStorageAnalyticsAfecFeature = ko.observable(false);
|
||||||
this.hasStorageAnalyticsAfecFeature.subscribe((enabled: boolean) => this.refreshCommandBarButtons());
|
this.hasStorageAnalyticsAfecFeature.subscribe((enabled: boolean) => this.refreshCommandBarButtons());
|
||||||
this.isSynapseLinkUpdating = ko.observable<boolean>(false);
|
this.isSynapseLinkUpdating = ko.observable<boolean>(false);
|
||||||
@@ -249,7 +256,7 @@ export default class Explorer {
|
|||||||
this._isAfecFeatureRegistered(Constants.AfecFeatures.StorageAnalytics).then((isRegistered) =>
|
this._isAfecFeatureRegistered(Constants.AfecFeatures.StorageAnalytics).then((isRegistered) =>
|
||||||
this.hasStorageAnalyticsAfecFeature(isRegistered)
|
this.hasStorageAnalyticsAfecFeature(isRegistered)
|
||||||
);
|
);
|
||||||
Promise.all([this._refreshNotebooksEnabledStateForAccount(), this._refreshSparkEnabledStateForAccount()]).then(
|
Promise.all([this._refreshNotebooksEnabledStateForAccount(), this.refreshSparkEnabledStateForAccount()]).then(
|
||||||
async () => {
|
async () => {
|
||||||
this.isNotebookEnabled(
|
this.isNotebookEnabled(
|
||||||
userContext.authType !== AuthType.ResourceToken &&
|
userContext.authType !== AuthType.ResourceToken &&
|
||||||
@@ -272,7 +279,7 @@ export default class Explorer {
|
|||||||
|
|
||||||
this.isSparkEnabled(
|
this.isSparkEnabled(
|
||||||
(this.isNotebookEnabled() &&
|
(this.isNotebookEnabled() &&
|
||||||
this.isSparkEnabledForAccount() &&
|
this.isSparkEnabledForAccount &&
|
||||||
this.arcadiaWorkspaces() &&
|
this.arcadiaWorkspaces() &&
|
||||||
this.arcadiaWorkspaces().length > 0) ||
|
this.arcadiaWorkspaces().length > 0) ||
|
||||||
userContext.features.enableSpark
|
userContext.features.enableSpark
|
||||||
@@ -1586,34 +1593,6 @@ export default class Explorer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public _refreshSparkEnabledStateForAccount = async (): Promise<void> => {
|
|
||||||
const { subscriptionId, authType } = userContext;
|
|
||||||
const armEndpoint = configContext.ARM_ENDPOINT;
|
|
||||||
if (!subscriptionId || !armEndpoint || authType === AuthType.EncryptedToken) {
|
|
||||||
// explorer is not aware of the database account yet
|
|
||||||
this.isSparkEnabledForAccount(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const featureUri = `subscriptions/${subscriptionId}/providers/Microsoft.Features/providers/Microsoft.DocumentDb/features/${Constants.AfecFeatures.Spark}`;
|
|
||||||
const resourceProviderClient = new ResourceProviderClientFactory().getOrCreate(featureUri);
|
|
||||||
try {
|
|
||||||
const sparkNotebooksFeature: DataModels.AfecFeature = await resourceProviderClient.getAsync(
|
|
||||||
featureUri,
|
|
||||||
Constants.ArmApiVersions.armFeatures
|
|
||||||
);
|
|
||||||
const isEnabled =
|
|
||||||
(sparkNotebooksFeature &&
|
|
||||||
sparkNotebooksFeature.properties &&
|
|
||||||
sparkNotebooksFeature.properties.state === "Registered") ||
|
|
||||||
false;
|
|
||||||
this.isSparkEnabledForAccount(isEnabled);
|
|
||||||
} catch (error) {
|
|
||||||
Logger.logError(getErrorMessage(error), "Explorer/isSparkEnabledForAccount");
|
|
||||||
this.isSparkEnabledForAccount(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public _isAfecFeatureRegistered = async (featureName: string): Promise<boolean> => {
|
public _isAfecFeatureRegistered = async (featureName: string): Promise<boolean> => {
|
||||||
const { subscriptionId, authType } = userContext;
|
const { subscriptionId, authType } = userContext;
|
||||||
const armEndpoint = configContext.ARM_ENDPOINT;
|
const armEndpoint = configContext.ARM_ENDPOINT;
|
||||||
@@ -1842,6 +1821,39 @@ export default class Explorer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async openNotebookViewer(notebookUrl: string) {
|
||||||
|
const title = path.basename(notebookUrl);
|
||||||
|
const hashLocation = notebookUrl;
|
||||||
|
const NotebookViewerTab = await (
|
||||||
|
await import(/* webpackChunkName: "NotebookViewerTab" */ "./Tabs/NotebookViewerTab")
|
||||||
|
).default;
|
||||||
|
|
||||||
|
const notebookViewerTab = this.tabsManager.getTabs(ViewModels.CollectionTabKind.NotebookV2).find((tab) => {
|
||||||
|
return tab.hashLocation() == hashLocation && tab instanceof NotebookViewerTab && tab.notebookUrl === notebookUrl;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (notebookViewerTab) {
|
||||||
|
this.tabsManager.activateNewTab(notebookViewerTab);
|
||||||
|
} else {
|
||||||
|
const notebookViewerTab = new NotebookViewerTab({
|
||||||
|
account: userContext.databaseAccount,
|
||||||
|
tabKind: ViewModels.CollectionTabKind.NotebookViewer,
|
||||||
|
node: null,
|
||||||
|
title: title,
|
||||||
|
tabPath: title,
|
||||||
|
collection: null,
|
||||||
|
hashLocation: hashLocation,
|
||||||
|
isTabsContentExpanded: ko.observable(true),
|
||||||
|
onLoadStartKey: null,
|
||||||
|
onUpdateTabsButtons: this.onUpdateTabsButtons,
|
||||||
|
container: this,
|
||||||
|
notebookUrl,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.tabsManager.activateNewTab(notebookViewerTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public onNewCollectionClicked(databaseId?: string): void {
|
public onNewCollectionClicked(databaseId?: string): void {
|
||||||
if (userContext.apiType === "Cassandra") {
|
if (userContext.apiType === "Cassandra") {
|
||||||
this.cassandraAddCollectionPane.open();
|
this.cassandraAddCollectionPane.open();
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export class EditorNeighborsComponent extends React.Component<EditorNeighborsCom
|
|||||||
this.addNewEdgeToNeighbor = this.props.isSource ? this.addNewEdgeToSource : this.addNewEdgeToTarget;
|
this.addNewEdgeToNeighbor = this.props.isSource ? this.addNewEdgeToSource : this.addNewEdgeToTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
// Show empty text boxes by default if no neighbor for convenience
|
// Show empty text boxes by default if no neighbor for convenience
|
||||||
if (this.props.editedNeighbors.currentNeighbors.length === 0) {
|
if (this.props.editedNeighbors.currentNeighbors.length === 0) {
|
||||||
if (this.props.isSource) {
|
if (this.props.isSource) {
|
||||||
@@ -45,7 +45,7 @@ export class EditorNeighborsComponent extends React.Component<EditorNeighborsCom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const neighborTitle = this.props.isSource
|
const neighborTitle = this.props.isSource
|
||||||
? EditorNeighborsComponent.SOURCE_TITLE
|
? EditorNeighborsComponent.SOURCE_TITLE
|
||||||
: EditorNeighborsComponent.TARGET_TITLE;
|
: EditorNeighborsComponent.TARGET_TITLE;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export class EditorNodePropertiesComponent extends React.Component<EditorNodePro
|
|||||||
public static readonly VERTEX_PROPERTY_TYPES = ["string", "number", "boolean" /* 'null' */]; // TODO Enable null when fully supported by backend
|
public static readonly VERTEX_PROPERTY_TYPES = ["string", "number", "boolean" /* 'null' */]; // TODO Enable null when fully supported by backend
|
||||||
private static readonly DEFAULT_PROPERTY_TYPE = "string";
|
private static readonly DEFAULT_PROPERTY_TYPE = "string";
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<table className="propertyTable">
|
<table className="propertyTable">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@@ -965,7 +965,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ************* React life-cycle methods *********** */
|
/* ************* React life-cycle methods *********** */
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const currentTabIndex = ((resultDisplay: ResultDisplay): number => {
|
const currentTabIndex = ((resultDisplay: ResultDisplay): number => {
|
||||||
switch (resultDisplay) {
|
switch (resultDisplay) {
|
||||||
case ResultDisplay.Graph:
|
case ResultDisplay.Graph:
|
||||||
@@ -1022,10 +1022,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentWillUnmount(): void {
|
public componentWillUnmount(): void {
|
||||||
this.gremlinClient.destroy();
|
this.gremlinClient.destroy();
|
||||||
}
|
}
|
||||||
public override componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
if (this.props.onLoadStartKey != null && this.props.onLoadStartKey != undefined) {
|
if (this.props.onLoadStartKey != null && this.props.onLoadStartKey != undefined) {
|
||||||
TelemetryProcessor.traceSuccess(
|
TelemetryProcessor.traceSuccess(
|
||||||
Action.Tab,
|
Action.Tab,
|
||||||
@@ -1069,7 +1069,7 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
public componentDidUpdate(): void {
|
||||||
this.onIsPropertyPaneEditing(this.isPropertyPaneEditing());
|
this.onIsPropertyPaneEditing(this.isPropertyPaneEditing());
|
||||||
this.onIsNewVertexDisabledChange(this.isNewVertexDisabled());
|
this.onIsNewVertexDisabledChange(this.isNewVertexDisabled());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,20 +18,20 @@ export class GraphVizComponent extends React.Component<GraphVizComponentProps> {
|
|||||||
this.forceGraph = new D3ForceGraph(this.props.forceGraphParams);
|
this.forceGraph = new D3ForceGraph(this.props.forceGraphParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
this.forceGraph.init(this.rootNode);
|
this.forceGraph.init(this.rootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override shouldComponentUpdate(): boolean {
|
public shouldComponentUpdate(): boolean {
|
||||||
// Prevents component re-rendering
|
// Prevents component re-rendering
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentWillUnmount(): void {
|
public componentWillUnmount(): void {
|
||||||
this.forceGraph.destroy();
|
this.forceGraph.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<svg id="maingraph" ref={(elt: Element) => this.setRef(elt)}>
|
<svg id="maingraph" ref={(elt: Element) => this.setRef(elt)}>
|
||||||
<title>Main Graph</title>
|
<title>Main Graph</title>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ interface LeftPaneComponentProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class LeftPaneComponent extends React.Component<LeftPaneComponentProps> {
|
export class LeftPaneComponent extends React.Component<LeftPaneComponentProps> {
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="leftPane">
|
<div className="leftPane">
|
||||||
<div className="paneTitle leftPaneResults">Results</div>
|
<div className="paneTitle leftPaneResults">Results</div>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ interface MiddlePaneComponentProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MiddlePaneComponent extends React.Component<MiddlePaneComponentProps> {
|
export class MiddlePaneComponent extends React.Component<MiddlePaneComponentProps> {
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="middlePane">
|
<div className="middlePane">
|
||||||
<div className="graphTitle">
|
<div className="graphTitle">
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export class NodePropertiesComponent extends React.Component<
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
if (!this.props.node) {
|
if (!this.props.node) {
|
||||||
return <span />;
|
return <span />;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export class QueryContainerComponent extends React.Component<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="queryContainer">
|
<div className="queryContainer">
|
||||||
<InputTypeaheadComponent.InputTypeaheadComponent
|
<InputTypeaheadComponent.InputTypeaheadComponent
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export class ReadOnlyNeighborsComponent extends React.Component<ReadOnlyNeighbor
|
|||||||
private static readonly NO_TARGETS_LABEL = "No targets found";
|
private static readonly NO_TARGETS_LABEL = "No targets found";
|
||||||
private static readonly TARGET_TITLE = "Target";
|
private static readonly TARGET_TITLE = "Target";
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const neighbors = this.props.isSource ? this.props.node.sources : this.props.node.targets;
|
const neighbors = this.props.isSource ? this.props.node.sources : this.props.node.targets;
|
||||||
const noNeighborsLabel = this.props.isSource
|
const noNeighborsLabel = this.props.isSource
|
||||||
? ReadOnlyNeighborsComponent.NO_SOURCES_LABEL
|
? ReadOnlyNeighborsComponent.NO_SOURCES_LABEL
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export interface ReadOnlyNodePropertiesComponentProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ReadOnlyNodePropertiesComponent extends React.Component<ReadOnlyNodePropertiesComponentProps> {
|
export class ReadOnlyNodePropertiesComponent extends React.Component<ReadOnlyNodePropertiesComponentProps> {
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<table className="roPropertyTable propertyTable">
|
<table className="roPropertyTable propertyTable">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@@ -10,17 +10,17 @@ interface MemoryTrackerProps {
|
|||||||
export class MemoryTrackerComponent extends React.Component<MemoryTrackerProps> {
|
export class MemoryTrackerComponent extends React.Component<MemoryTrackerProps> {
|
||||||
private memoryUsageInfoSubscription: Subscription;
|
private memoryUsageInfoSubscription: Subscription;
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
this.memoryUsageInfoSubscription = this.props.memoryUsageInfo.subscribe(() => {
|
this.memoryUsageInfoSubscription = this.props.memoryUsageInfo.subscribe(() => {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentWillUnmount(): void {
|
public componentWillUnmount(): void {
|
||||||
this.memoryUsageInfoSubscription && this.memoryUsageInfoSubscription.dispose();
|
this.memoryUsageInfoSubscription && this.memoryUsageInfoSubscription.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const memoryUsageInfo: MemoryUsageInfo = this.props.memoryUsageInfo();
|
const memoryUsageInfo: MemoryUsageInfo = this.props.memoryUsageInfo();
|
||||||
if (!memoryUsageInfo) {
|
if (!memoryUsageInfo) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class ControlBarComponent extends React.Component<ControlBarComponentProp
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
if (!this.props.buttons || this.props.buttons.length < 1) {
|
if (!this.props.buttons || this.props.buttons.length < 1) {
|
||||||
return <React.Fragment />;
|
return <React.Fragment />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export class NotificationConsoleComponent extends React.Component<
|
|||||||
this.prevHeaderStatus = undefined;
|
this.prevHeaderStatus = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(
|
public componentDidUpdate(
|
||||||
prevProps: NotificationConsoleComponentProps,
|
prevProps: NotificationConsoleComponentProps,
|
||||||
prevState: NotificationConsoleComponentState
|
prevState: NotificationConsoleComponentState
|
||||||
): void {
|
): void {
|
||||||
@@ -102,7 +102,7 @@ export class NotificationConsoleComponent extends React.Component<
|
|||||||
this.consoleHeaderElement = element;
|
this.consoleHeaderElement = element;
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const numInProgress = this.state.allConsoleData.filter(
|
const numInProgress = this.state.allConsoleData.filter(
|
||||||
(data: ConsoleData) => data.type === ConsoleDataType.InProgress
|
(data: ConsoleData) => data.type === ConsoleDataType.InProgress
|
||||||
).length;
|
).length;
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import { default as Contents } from "./contents";
|
|||||||
export class NotebookComponent extends React.Component<{ contentRef: ContentRef }> {
|
export class NotebookComponent extends React.Component<{ contentRef: ContentRef }> {
|
||||||
notificationSystem!: ReactNotificationSystem;
|
notificationSystem!: ReactNotificationSystem;
|
||||||
|
|
||||||
public override shouldComponentUpdate(nextProps: { contentRef: ContentRef }): boolean {
|
shouldComponentUpdate(nextProps: { contentRef: ContentRef }): boolean {
|
||||||
return nextProps.contentRef !== this.props.contentRef;
|
return nextProps.contentRef !== this.props.contentRef;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="notebookComponentContainer">
|
<div className="notebookComponentContainer">
|
||||||
<Contents contentRef={this.props.contentRef} />
|
<Contents contentRef={this.props.contentRef} />
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export class NotebookComponentAdapter extends NotebookComponentBootstrapper impl
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override renderExtraComponent = (): JSX.Element => {
|
protected renderExtraComponent = (): JSX.Element => {
|
||||||
return <VirtualCommandBarComponent contentRef={this.contentRef} onRender={this.onUpdateKernelInfo} />;
|
return <VirtualCommandBarComponent contentRef={this.contentRef} onRender={this.onUpdateKernelInfo} />;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ class VirtualCommandBarComponent extends React.Component<VirtualCommandBarCompon
|
|||||||
this.state = {};
|
this.state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override shouldComponentUpdate(nextProps: VirtualCommandBarComponentProps): boolean {
|
shouldComponentUpdate(nextProps: VirtualCommandBarComponentProps): boolean {
|
||||||
return (
|
return (
|
||||||
this.props.kernelStatus !== nextProps.kernelStatus ||
|
this.props.kernelStatus !== nextProps.kernelStatus ||
|
||||||
this.props.kernelSpecName !== nextProps.kernelSpecName ||
|
this.props.kernelSpecName !== nextProps.kernelSpecName ||
|
||||||
@@ -24,7 +24,7 @@ public override shouldComponentUpdate(nextProps: VirtualCommandBarComponentProps
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
this.props.onRender && this.props.onRender();
|
this.props.onRender && this.props.onRender();
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ export class File extends React.PureComponent<FileProps> {
|
|||||||
return choice;
|
return choice;
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
const choice = this.getChoice();
|
const choice = this.getChoice();
|
||||||
|
|
||||||
// Right now we only handle one kind of editor
|
// Right now we only handle one kind of editor
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ interface TextFileState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EditorPlaceholder extends React.PureComponent<MonacoEditorProps> {
|
class EditorPlaceholder extends React.PureComponent<MonacoEditorProps> {
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
// TODO: Show a little blocky placeholder
|
// TODO: Show a little blocky placeholder
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -53,13 +53,13 @@ export class TextFile extends React.PureComponent<TextFileProps, TextFileState>
|
|||||||
this.props.handleChange(source);
|
this.props.handleChange(source);
|
||||||
};
|
};
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
import(/* webpackChunkName: "monaco-editor" */ "@nteract/monaco-editor").then((module) => {
|
import(/* webpackChunkName: "monaco-editor" */ "@nteract/monaco-editor").then((module) => {
|
||||||
this.setState({ Editor: module.default });
|
this.setState({ Editor: module.default });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
const Editor = this.state.Editor;
|
const Editor = this.state.Editor;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ class Contents extends React.PureComponent<ContentsProps> {
|
|||||||
SAVE: ["ctrl+s", "ctrl+shift+s", "meta+s", "meta+shift+s"],
|
SAVE: ["ctrl+s", "ctrl+shift+s", "meta+s", "meta+shift+s"],
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
const { contentRef, handlers } = this.props;
|
const { contentRef, handlers } = this.props;
|
||||||
|
|
||||||
if (!contentRef) {
|
if (!contentRef) {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export interface NotebookRendererProps {
|
|||||||
* This is the class that uses nteract to render a read-only notebook.
|
* This is the class that uses nteract to render a read-only notebook.
|
||||||
*/
|
*/
|
||||||
class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
class NotebookReadOnlyRenderer extends React.Component<NotebookRendererProps> {
|
||||||
public override componentDidMount() {
|
componentDidMount() {
|
||||||
if (!userContext.features.sandboxNotebookOutputs) {
|
if (!userContext.features.sandboxNotebookOutputs) {
|
||||||
loadTransform(this.props as any);
|
loadTransform(this.props as any);
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ public override componentDidMount() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="NotebookReadOnlyRender">
|
<div className="NotebookReadOnlyRender">
|
||||||
<Cells contentRef={this.props.contentRef}>
|
<Cells contentRef={this.props.contentRef}>
|
||||||
|
|||||||
@@ -68,22 +68,22 @@ class BaseNotebookRenderer extends React.Component<NotebookRendererProps> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount() {
|
componentDidMount() {
|
||||||
if (!userContext.features.sandboxNotebookOutputs) {
|
if (!userContext.features.sandboxNotebookOutputs) {
|
||||||
loadTransform(this.props as any);
|
loadTransform(this.props as any);
|
||||||
}
|
}
|
||||||
this.props.updateNotebookParentDomElt(this.props.contentRef, this.notebookRendererRef.current);
|
this.props.updateNotebookParentDomElt(this.props.contentRef, this.notebookRendererRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
this.props.updateNotebookParentDomElt(this.props.contentRef, this.notebookRendererRef.current);
|
this.props.updateNotebookParentDomElt(this.props.contentRef, this.notebookRendererRef.current);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.props.updateNotebookParentDomElt(this.props.contentRef, undefined);
|
this.props.updateNotebookParentDomElt(this.props.contentRef, undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="NotebookRendererContainer">
|
<div className="NotebookRendererContainer">
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ interface DispatchProps {
|
|||||||
type Props = StateProps & DispatchProps & ComponentProps;
|
type Props = StateProps & DispatchProps & ComponentProps;
|
||||||
|
|
||||||
export class PromptPure extends React.Component<Props> {
|
export class PromptPure extends React.Component<Props> {
|
||||||
public override render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="nteract-cell-prompt">
|
<div className="nteract-cell-prompt">
|
||||||
{this.props.children({
|
{this.props.children({
|
||||||
|
|||||||
@@ -45,14 +45,14 @@ const BarContainer = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export class StatusBar extends React.Component<Props> {
|
export class StatusBar extends React.Component<Props> {
|
||||||
public override shouldComponentUpdate(nextProps: Props): boolean {
|
shouldComponentUpdate(nextProps: Props): boolean {
|
||||||
if (this.props.lastSaved !== nextProps.lastSaved || this.props.kernelStatus !== nextProps.kernelStatus) {
|
if (this.props.lastSaved !== nextProps.lastSaved || this.props.kernelStatus !== nextProps.kernelStatus) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render() {
|
render() {
|
||||||
const name = this.props.kernelSpecDisplayName || "Loading...";
|
const name = this.props.kernelSpecDisplayName || "Loading...";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ interface StateProps {
|
|||||||
class BaseToolbar extends React.PureComponent<ComponentProps & DispatchProps & StateProps> {
|
class BaseToolbar extends React.PureComponent<ComponentProps & DispatchProps & StateProps> {
|
||||||
static contextType = CellToolbarContext;
|
static contextType = CellToolbarContext;
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
let items: IContextualMenuItem[] = [];
|
let items: IContextualMenuItem[] = [];
|
||||||
|
|
||||||
if (this.props.cellType === "code") {
|
if (this.props.cellType === "code") {
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ export class PureCellCreator extends React.PureComponent<CellCreatorProps> {
|
|||||||
this.props.createCell("code", this.props.above);
|
this.props.createCell("code", this.props.above);
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<CreatorHoverMask>
|
<CreatorHoverMask>
|
||||||
<CreatorHoverRegion>
|
<CreatorHoverRegion>
|
||||||
@@ -171,7 +171,7 @@ class CellCreator extends React.PureComponent<ComponentProps & DispatchProps & S
|
|||||||
: createCellBelow({ cellType: type, id, source: "", contentRef });
|
: createCellBelow({ cellType: type, id, source: "", contentRef });
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{this.props.isFirstCell && (
|
{this.props.isFirstCell && (
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ interface StateProps {
|
|||||||
* Displays "Cell <index>"
|
* Displays "Cell <index>"
|
||||||
*/
|
*/
|
||||||
class CellLabeler extends React.Component<ComponentProps & StateProps> {
|
class CellLabeler extends React.Component<ComponentProps & StateProps> {
|
||||||
public override render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="CellLabeler">
|
<div className="CellLabeler">
|
||||||
<div className="CellLabel">Cell {this.props.cellIndex + 1}</div>
|
<div className="CellLabel">Cell {this.props.cellIndex + 1}</div>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ interface DispatchProps {
|
|||||||
* HoverableCell sets the hovered cell
|
* HoverableCell sets the hovered cell
|
||||||
*/
|
*/
|
||||||
class HoverableCell extends React.Component<ComponentProps & DispatchProps> {
|
class HoverableCell extends React.Component<ComponentProps & DispatchProps> {
|
||||||
public override render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="HoverableCell" onMouseEnter={this.props.hover} onMouseLeave={this.props.unHover}>
|
<div className="HoverableCell" onMouseEnter={this.props.hover} onMouseLeave={this.props.unHover}>
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
|
|||||||
@@ -173,11 +173,11 @@ function collectTarget(
|
|||||||
export class DraggableCellView extends React.Component<Props & DnDSourceProps & DnDTargetProps, State> {
|
export class DraggableCellView extends React.Component<Props & DnDSourceProps & DnDTargetProps, State> {
|
||||||
el?: HTMLDivElement | null;
|
el?: HTMLDivElement | null;
|
||||||
|
|
||||||
public override state = {
|
state = {
|
||||||
hoverUpperHalf: true,
|
hoverUpperHalf: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
const connectDragPreview = this.props.connectDragPreview;
|
const connectDragPreview = this.props.connectDragPreview;
|
||||||
const img = new (window as any).Image();
|
const img = new (window as any).Image();
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ public override componentDidMount(): void {
|
|||||||
focusCell({ id, contentRef });
|
focusCell({ id, contentRef });
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render() {
|
render() {
|
||||||
return this.props.connectDropTarget(
|
return this.props.connectDropTarget(
|
||||||
// Sadly connectDropTarget _has_ to take a React element for a DOM element (no styled-divs)
|
// Sadly connectDropTarget _has_ to take a React element for a DOM element (no styled-divs)
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -47,15 +47,15 @@ export class HijackScroll extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(prevProps: Props) {
|
componentDidUpdate(prevProps: Props) {
|
||||||
this.scrollIntoViewIfNeeded(prevProps.focused);
|
this.scrollIntoViewIfNeeded(prevProps.focused);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
this.scrollIntoViewIfNeeded();
|
this.scrollIntoViewIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={this.props.selectCell}
|
onClick={this.props.selectCell}
|
||||||
|
|||||||
@@ -31,18 +31,18 @@ export class KeyboardShortcuts extends React.Component<Props> {
|
|||||||
this.keyDown = this.keyDown.bind(this);
|
this.keyDown = this.keyDown.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override shouldComponentUpdate(nextProps: Props) {
|
shouldComponentUpdate(nextProps: Props) {
|
||||||
const newContentRef = this.props.contentRef !== nextProps.contentRef;
|
const newContentRef = this.props.contentRef !== nextProps.contentRef;
|
||||||
const newFocusedCell = this.props.focusedCell !== nextProps.focusedCell;
|
const newFocusedCell = this.props.focusedCell !== nextProps.focusedCell;
|
||||||
const newCellOrder = this.props.cellOrder && this.props.cellOrder.size !== nextProps.cellOrder.size;
|
const newCellOrder = this.props.cellOrder && this.props.cellOrder.size !== nextProps.cellOrder.size;
|
||||||
return newContentRef || newFocusedCell || newCellOrder;
|
return newContentRef || newFocusedCell || newCellOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
document.addEventListener("keydown", this.keyDown);
|
document.addEventListener("keydown", this.keyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentWillUnmount(): void {
|
componentWillUnmount(): void {
|
||||||
document.removeEventListener("keydown", this.keyDown);
|
document.removeEventListener("keydown", this.keyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ public override componentWillUnmount(): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render() {
|
render() {
|
||||||
return <React.Fragment>{this.props.children}</React.Fragment>;
|
return <React.Fragment>{this.props.children}</React.Fragment>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ export const Source = styled(BareSource)`
|
|||||||
width: -moz-available;
|
width: -moz-available;
|
||||||
`;
|
`;
|
||||||
export class PureMarkdownCell extends React.Component<ComponentProps & DispatchProps & StateProps> {
|
export class PureMarkdownCell extends React.Component<ComponentProps & DispatchProps & StateProps> {
|
||||||
public override render() {
|
render() {
|
||||||
const { contentRef, id, cell, children } = this.props;
|
const { contentRef, id, cell, children } = this.props;
|
||||||
|
|
||||||
const { isEditorFocused, isCellFocused, markdownOptions } = this.props;
|
const { isEditorFocused, isCellFocused, markdownOptions } = this.props;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ interface DispatchProps {
|
|||||||
export class SandboxOutputs extends React.PureComponent<ComponentProps & StateProps & DispatchProps> {
|
export class SandboxOutputs extends React.PureComponent<ComponentProps & StateProps & DispatchProps> {
|
||||||
private childWindow: Window;
|
private childWindow: Window;
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
// Using min-width to set the width of the iFrame, works around an issue in iOS that can prevent the iFrame from sizing correctly.
|
// Using min-width to set the width of the iFrame, works around an issue in iOS that can prevent the iFrame from sizing correctly.
|
||||||
return (
|
return (
|
||||||
<IframeResizer
|
<IframeResizer
|
||||||
@@ -72,11 +72,11 @@ public override render(): JSX.Element {
|
|||||||
postRobot.send(this.childWindow, "props", props);
|
postRobot.send(this.childWindow, "props", props);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
this.sendPropsToFrame();
|
this.sendPropsToFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(): void {
|
componentDidUpdate(): void {
|
||||||
this.sendPropsToFrame();
|
this.sendPropsToFrame();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export class SchemaAnalyzerComponent extends React.Component<
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
loadTransform(this.props);
|
loadTransform(this.props);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ public override componentDidMount(): void {
|
|||||||
this.props.runCell(this.props.contentRef, this.props.firstCellId);
|
this.props.runCell(this.props.contentRef, this.props.firstCellId);
|
||||||
};
|
};
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
const { firstCellId: id, contentRef, kernelStatus, outputs } = this.props;
|
const { firstCellId: id, contentRef, kernelStatus, outputs } = this.props;
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return <></>;
|
return <></>;
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export class SchemaAnalyzerComponentAdapter extends NotebookComponentBootstrappe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override renderComponent(): JSX.Element {
|
public renderComponent(): JSX.Element {
|
||||||
const props = {
|
const props = {
|
||||||
contentRef: this.contentRef,
|
contentRef: this.contentRef,
|
||||||
kernelRef: this.kernelRef,
|
kernelRef: this.kernelRef,
|
||||||
|
|||||||
@@ -438,7 +438,7 @@
|
|||||||
<!-- Provision collection throughput - end -->
|
<!-- Provision collection throughput - end -->
|
||||||
|
|
||||||
<!-- Custom indexes for mongo checkbox - start -->
|
<!-- Custom indexes for mongo checkbox - start -->
|
||||||
<div class="pkPadding" data-bind="visible: isEnableMongoCapabilityEnabled()">
|
<div class="pkPadding" data-bind="visible: container.isEnableMongoCapabilityPresent()">
|
||||||
<p>
|
<p>
|
||||||
<span class="addCollectionLabel">Indexing</span>
|
<span class="addCollectionLabel">Indexing</span>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
|||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import * as AutoPilotUtils from "../../Utils/AutoPilotUtils";
|
import * as AutoPilotUtils from "../../Utils/AutoPilotUtils";
|
||||||
import { isCapabilityEnabled } from "../../Utils/CapabilityUtils";
|
|
||||||
import * as PricingUtils from "../../Utils/PricingUtils";
|
import * as PricingUtils from "../../Utils/PricingUtils";
|
||||||
import { DynamicListItem } from "../Controls/DynamicList/DynamicListComponent";
|
import { DynamicListItem } from "../Controls/DynamicList/DynamicListComponent";
|
||||||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||||
@@ -36,7 +35,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
public collectionWithThroughputInShared: ko.Observable<boolean>;
|
public collectionWithThroughputInShared: ko.Observable<boolean>;
|
||||||
public databaseCreateNewShared: ko.Observable<boolean>;
|
public databaseCreateNewShared: ko.Observable<boolean>;
|
||||||
public databaseHasSharedOffer: ko.Observable<boolean>;
|
public databaseHasSharedOffer: ko.Observable<boolean>;
|
||||||
public override formErrorsDetails: ko.Observable<string>;
|
public formErrorsDetails: ko.Observable<string>;
|
||||||
public formWarnings: ko.Observable<string>;
|
public formWarnings: ko.Observable<string>;
|
||||||
public partitionKey: ko.Observable<string>;
|
public partitionKey: ko.Observable<string>;
|
||||||
public partitionKeyName: ko.Computed<string>;
|
public partitionKeyName: ko.Computed<string>;
|
||||||
@@ -96,7 +95,6 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
public shouldCreateMongoWildcardIndex: ko.Observable<boolean>;
|
public shouldCreateMongoWildcardIndex: ko.Observable<boolean>;
|
||||||
|
|
||||||
private _isSynapseLinkEnabled: ko.Computed<boolean>;
|
private _isSynapseLinkEnabled: ko.Computed<boolean>;
|
||||||
private isEnableMongoCapabilityEnabled: ko.Observable<boolean>;
|
|
||||||
|
|
||||||
constructor(options: AddCollectionPaneOptions) {
|
constructor(options: AddCollectionPaneOptions) {
|
||||||
super(options);
|
super(options);
|
||||||
@@ -636,8 +634,6 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.isEnableMongoCapabilityEnabled = ko.observable(isCapabilityEnabled("EnableMongo"));
|
|
||||||
|
|
||||||
this.shouldCreateMongoWildcardIndex = ko.observable(this.container.isMongoIndexingEnabled());
|
this.shouldCreateMongoWildcardIndex = ko.observable(this.container.isMongoIndexingEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +654,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
public override async open(databaseId?: string) {
|
public async open(databaseId?: string) {
|
||||||
super.open();
|
super.open();
|
||||||
// TODO: Figure out if a database level partition split is about to happen once shared throughput read is available
|
// TODO: Figure out if a database level partition split is about to happen once shared throughput read is available
|
||||||
this.formWarnings("");
|
this.formWarnings("");
|
||||||
@@ -752,7 +748,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
return this._getThroughput();
|
return this._getThroughput();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override submit() {
|
public submit() {
|
||||||
if (!this.isValid()) {
|
if (!this.isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -912,7 +908,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override resetData() {
|
public resetData() {
|
||||||
this.collectionId("");
|
this.collectionId("");
|
||||||
this.databaseId("");
|
this.databaseId("");
|
||||||
this.partitionKey("");
|
this.partitionKey("");
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
|||||||
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||||
import { userContext } from "../../UserContext";
|
import { userContext } from "../../UserContext";
|
||||||
import { getCollectionName } from "../../Utils/APITypeUtils";
|
import { getCollectionName } from "../../Utils/APITypeUtils";
|
||||||
import { isCapabilityEnabled } from "../../Utils/CapabilityUtils";
|
|
||||||
import { getUpsellMessage } from "../../Utils/PricingUtils";
|
import { getUpsellMessage } from "../../Utils/PricingUtils";
|
||||||
import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent";
|
import { CollapsibleSectionComponent } from "../Controls/CollapsiblePanel/CollapsibleSectionComponent";
|
||||||
import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput";
|
import { ThroughputInput } from "../Controls/ThroughputInput/ThroughputInput";
|
||||||
@@ -81,7 +80,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
isSharded: userContext.apiType !== "Tables",
|
isSharded: userContext.apiType !== "Tables",
|
||||||
partitionKey: "",
|
partitionKey: "",
|
||||||
enableDedicatedThroughput: false,
|
enableDedicatedThroughput: false,
|
||||||
createMongoWildCardIndex: isCapabilityEnabled("EnableMongo"),
|
createMongoWildCardIndex: true,
|
||||||
useHashV2: false,
|
useHashV2: false,
|
||||||
enableAnalyticalStore: false,
|
enableAnalyticalStore: false,
|
||||||
uniqueKeys: [],
|
uniqueKeys: [],
|
||||||
@@ -91,7 +90,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<form className="panelFormWrapper" onSubmit={this.submit.bind(this)}>
|
<form className="panelFormWrapper" onSubmit={this.submit.bind(this)}>
|
||||||
{this.state.errorMessage && (
|
{this.state.errorMessage && (
|
||||||
@@ -526,7 +525,7 @@ public override render(): JSX.Element {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Stack className="panelGroupSpacing" id="collapsibleSectionContent">
|
<Stack className="panelGroupSpacing" id="collapsibleSectionContent">
|
||||||
{isCapabilityEnabled("EnableMongo") && (
|
{userContext.databaseAccount.properties.capabilities.find((c) => c.name === "EnableMongo") && (
|
||||||
<Stack className="panelGroupSpacing">
|
<Stack className="panelGroupSpacing">
|
||||||
<Stack horizontal>
|
<Stack horizontal>
|
||||||
<span className="mandatoryStar">* </span>
|
<span className="mandatoryStar">* </span>
|
||||||
@@ -852,7 +851,7 @@ public override render(): JSX.Element {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return properties.capabilities?.some(
|
return properties.capabilities.some(
|
||||||
(capability) => capability.name === Constants.CapabilityNames.EnableStorageAnalytics
|
(capability) => capability.name === Constants.CapabilityNames.EnableStorageAnalytics
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||||||
public databaseIdTooltipText: ko.Computed<string>;
|
public databaseIdTooltipText: ko.Computed<string>;
|
||||||
public databaseLevelThroughputTooltipText: ko.Computed<string>;
|
public databaseLevelThroughputTooltipText: ko.Computed<string>;
|
||||||
public databaseCreateNewShared: ko.Observable<boolean>;
|
public databaseCreateNewShared: ko.Observable<boolean>;
|
||||||
public override formErrorsDetails: ko.Observable<string>;
|
public formErrorsDetails: ko.Observable<string>;
|
||||||
public throughput: ViewModels.Editable<number>;
|
public throughput: ViewModels.Editable<number>;
|
||||||
public maxThroughputRU: ko.Observable<number>;
|
public maxThroughputRU: ko.Observable<number>;
|
||||||
public minThroughputRU: ko.Observable<number>;
|
public minThroughputRU: ko.Observable<number>;
|
||||||
@@ -255,7 +255,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
public override open() {
|
public open() {
|
||||||
super.open();
|
super.open();
|
||||||
this.resetData();
|
this.resetData();
|
||||||
const addDatabasePaneOpenMessage = {
|
const addDatabasePaneOpenMessage = {
|
||||||
@@ -272,7 +272,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||||||
TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage);
|
TelemetryProcessor.trace(Action.CreateDatabase, ActionModifiers.Open, addDatabasePaneOpenMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override submit() {
|
public submit() {
|
||||||
if (!this._isValid()) {
|
if (!this._isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -317,7 +317,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override resetData() {
|
public resetData() {
|
||||||
this.databaseId("");
|
this.databaseId("");
|
||||||
this.databaseCreateNewShared(this.getSharedThroughputDefault());
|
this.databaseCreateNewShared(this.getSharedThroughputDefault());
|
||||||
this.isAutoPilotSelected(this.container.isAutoscaleDefaultEnabled());
|
this.isAutoPilotSelected(this.container.isAutoscaleDefaultEnabled());
|
||||||
|
|||||||
@@ -279,7 +279,7 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override open() {
|
public open() {
|
||||||
super.open();
|
super.open();
|
||||||
if (!this.container.isServerlessEnabled()) {
|
if (!this.container.isServerlessEnabled()) {
|
||||||
this.isAutoPilotSelected(this.container.isAutoscaleDefaultEnabled());
|
this.isAutoPilotSelected(this.container.isAutoscaleDefaultEnabled());
|
||||||
@@ -306,7 +306,7 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||||||
TelemetryProcessor.trace(Action.CreateCollection, ActionModifiers.Open, addCollectionPaneOpenMessage);
|
TelemetryProcessor.trace(Action.CreateCollection, ActionModifiers.Open, addCollectionPaneOpenMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override submit() {
|
public submit() {
|
||||||
if (!this._isValid()) {
|
if (!this._isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -436,7 +436,7 @@ export default class CassandraAddCollectionPane extends ContextualPaneBase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override resetData() {
|
public resetData() {
|
||||||
super.resetData();
|
super.resetData();
|
||||||
const throughputDefaults = this.container.collectionCreationDefaults.throughput;
|
const throughputDefaults = this.container.collectionCreationDefaults.throughput;
|
||||||
this.isAutoPilotSelected(this.container.isAutoscaleDefaultEnabled());
|
this.isAutoPilotSelected(this.container.isAutoscaleDefaultEnabled());
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export class GitHubReposPanel extends React.Component<IGitHubReposPanelProps, IG
|
|||||||
this.junoClient = this.props.junoClientProp;
|
this.junoClient = this.props.junoClientProp;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
this.open();
|
this.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,7 +431,7 @@ public override componentDidMount(): void {
|
|||||||
this.props.explorer.notebookManager?.gitHubOAuthService.startOAuth(scope);
|
this.props.explorer.notebookManager?.gitHubOAuthService.startOAuth(scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<form className="panelFormWrapper">
|
<form className="panelFormWrapper">
|
||||||
{this.state.errorMessage && (
|
{this.state.errorMessage && (
|
||||||
|
|||||||
@@ -92,7 +92,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -213,7 +212,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
|
|||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionPane": AddCollectionPane {
|
"addCollectionPane": AddCollectionPane {
|
||||||
"_isSynapseLinkEnabled": [Function],
|
"_isSynapseLinkEnabled": [Function],
|
||||||
@@ -243,7 +241,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -1215,7 +1212,7 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
|
|||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isServerlessEnabled": [Function],
|
"isServerlessEnabled": [Function],
|
||||||
"isSparkEnabled": [Function],
|
"isSparkEnabled": [Function],
|
||||||
"isSparkEnabledForAccount": [Function],
|
"isSparkEnabledForAccount": undefined,
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"junoClient": JunoClient {
|
"junoClient": JunoClient {
|
||||||
@@ -1234,6 +1231,7 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
|
|||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
|
"refreshSparkEnabledStateForAccount": undefined,
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
"resourceTokenCollection": [Function],
|
"resourceTokenCollection": [Function],
|
||||||
"resourceTokenCollectionId": [Function],
|
"resourceTokenCollectionId": [Function],
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export default class GraphStylingPane extends ContextualPaneBase {
|
|||||||
this.remoteConfig = config;
|
this.remoteConfig = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override close() {
|
public close() {
|
||||||
this.remoteConfig = null;
|
this.remoteConfig = null;
|
||||||
super.close();
|
super.close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import AddCollectionPaneTemplate from "./AddCollectionPane.html";
|
|||||||
import AddDatabasePaneTemplate from "./AddDatabasePane.html";
|
import AddDatabasePaneTemplate from "./AddDatabasePane.html";
|
||||||
import CassandraAddCollectionPaneTemplate from "./CassandraAddCollectionPane.html";
|
import CassandraAddCollectionPaneTemplate from "./CassandraAddCollectionPane.html";
|
||||||
import GraphStylingPaneTemplate from "./GraphStylingPane.html";
|
import GraphStylingPaneTemplate from "./GraphStylingPane.html";
|
||||||
|
import TableAddEntityPaneTemplate from "./Tables/TableAddEntityPane.html";
|
||||||
|
import TableEditEntityPaneTemplate from "./Tables/TableEditEntityPane.html";
|
||||||
|
|
||||||
export class PaneComponent {
|
export class PaneComponent {
|
||||||
constructor(data: any) {
|
constructor(data: any) {
|
||||||
@@ -36,6 +38,23 @@ export class GraphStylingPaneComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TableAddEntityPaneComponent {
|
||||||
|
constructor() {
|
||||||
|
return {
|
||||||
|
viewModel: PaneComponent,
|
||||||
|
template: TableAddEntityPaneTemplate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TableEditEntityPaneComponent {
|
||||||
|
constructor() {
|
||||||
|
return {
|
||||||
|
viewModel: PaneComponent,
|
||||||
|
template: TableEditEntityPaneTemplate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
export class CassandraAddCollectionPaneComponent {
|
export class CassandraAddCollectionPaneComponent {
|
||||||
constructor() {
|
constructor() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -27,15 +27,15 @@ export class PanelContainerComponent extends React.Component<PanelContainerProps
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
window.addEventListener("resize", () => this.setState({ height: this.getPanelHeight() }));
|
window.addEventListener("resize", () => this.setState({ height: this.getPanelHeight() }));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override componentWillUnmount(): void {
|
componentWillUnmount(): void {
|
||||||
window.removeEventListener("resize", () => this.setState({ height: this.getPanelHeight() }));
|
window.removeEventListener("resize", () => this.setState({ height: this.getPanelHeight() }));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
if (!this.props.panelContent) {
|
if (!this.props.panelContent) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -203,7 +202,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
|||||||
"visible": [Function],
|
"visible": [Function],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"_refreshSparkEnabledStateForAccount": [Function],
|
|
||||||
"_resetNotebookWorkspace": [Function],
|
"_resetNotebookWorkspace": [Function],
|
||||||
"addCollectionPane": AddCollectionPane {
|
"addCollectionPane": AddCollectionPane {
|
||||||
"_isSynapseLinkEnabled": [Function],
|
"_isSynapseLinkEnabled": [Function],
|
||||||
@@ -233,7 +231,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
|||||||
"id": "addcollectionpane",
|
"id": "addcollectionpane",
|
||||||
"isAnalyticalStorageOn": [Function],
|
"isAnalyticalStorageOn": [Function],
|
||||||
"isAutoPilotSelected": [Function],
|
"isAutoPilotSelected": [Function],
|
||||||
"isEnableMongoCapabilityEnabled": [Function],
|
|
||||||
"isExecuting": [Function],
|
"isExecuting": [Function],
|
||||||
"isFixedStorageSelected": [Function],
|
"isFixedStorageSelected": [Function],
|
||||||
"isFreeTierAccount": [Function],
|
"isFreeTierAccount": [Function],
|
||||||
@@ -1205,7 +1202,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
|||||||
"isSchemaEnabled": [Function],
|
"isSchemaEnabled": [Function],
|
||||||
"isServerlessEnabled": [Function],
|
"isServerlessEnabled": [Function],
|
||||||
"isSparkEnabled": [Function],
|
"isSparkEnabled": [Function],
|
||||||
"isSparkEnabledForAccount": [Function],
|
"isSparkEnabledForAccount": undefined,
|
||||||
"isSynapseLinkUpdating": [Function],
|
"isSynapseLinkUpdating": [Function],
|
||||||
"isTabsContentExpanded": [Function],
|
"isTabsContentExpanded": [Function],
|
||||||
"junoClient": JunoClient {
|
"junoClient": JunoClient {
|
||||||
@@ -1224,6 +1221,7 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
|
|||||||
"container": [Circular],
|
"container": [Circular],
|
||||||
},
|
},
|
||||||
"refreshNotebookList": [Function],
|
"refreshNotebookList": [Function],
|
||||||
|
"refreshSparkEnabledStateForAccount": undefined,
|
||||||
"refreshTreeTitle": [Function],
|
"refreshTreeTitle": [Function],
|
||||||
"resourceTokenCollection": [Function],
|
"resourceTokenCollection": [Function],
|
||||||
"resourceTokenCollectionId": [Function],
|
"resourceTokenCollectionId": [Function],
|
||||||
|
|||||||
225
src/Explorer/Panes/Tables/EditTableEntityPane.ts
Normal file
225
src/Explorer/Panes/Tables/EditTableEntityPane.ts
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
import * as ko from "knockout";
|
||||||
|
import _ from "underscore";
|
||||||
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
|
import Explorer from "../../Explorer";
|
||||||
|
import * as TableConstants from "../../Tables/Constants";
|
||||||
|
import * as Entities from "../../Tables/Entities";
|
||||||
|
import { CassandraAPIDataClient, CassandraTableKey } from "../../Tables/TableDataClient";
|
||||||
|
import * as TableEntityProcessor from "../../Tables/TableEntityProcessor";
|
||||||
|
import * as Utilities from "../../Tables/Utilities";
|
||||||
|
import EntityPropertyViewModel from "./EntityPropertyViewModel";
|
||||||
|
import TableEntityPane from "./TableEntityPane";
|
||||||
|
|
||||||
|
export default class EditTableEntityPane extends TableEntityPane {
|
||||||
|
container: Explorer;
|
||||||
|
visible: ko.Observable<boolean>;
|
||||||
|
|
||||||
|
public originEntity: Entities.ITableEntity;
|
||||||
|
public originalNumberOfProperties: number;
|
||||||
|
private originalDocument: any;
|
||||||
|
|
||||||
|
constructor(options: ViewModels.PaneOptions) {
|
||||||
|
super(options);
|
||||||
|
this.submitButtonText("Update Entity");
|
||||||
|
if (userContext.apiType === "Cassandra") {
|
||||||
|
this.submitButtonText("Update Row");
|
||||||
|
}
|
||||||
|
this.scrollId = ko.observable<string>("editEntityScroll");
|
||||||
|
}
|
||||||
|
|
||||||
|
public submit() {
|
||||||
|
if (!this.canApply()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let entity: Entities.ITableEntity = this.updateEntity(this.displayedAttributes());
|
||||||
|
this.container.tableDataClient
|
||||||
|
.updateDocument(this.tableViewModel.queryTablesTab.collection, this.originalDocument, entity)
|
||||||
|
.then((newEntity: Entities.ITableEntity) => {
|
||||||
|
var numberOfProperties = 0;
|
||||||
|
for (var property in newEntity) {
|
||||||
|
if (
|
||||||
|
property !== TableEntityProcessor.keyProperties.attachments &&
|
||||||
|
property !== TableEntityProcessor.keyProperties.etag &&
|
||||||
|
property !== TableEntityProcessor.keyProperties.resourceId &&
|
||||||
|
property !== TableEntityProcessor.keyProperties.self &&
|
||||||
|
(userContext.apiType !== "Cassandra" || property !== TableConstants.EntityKeyNames.RowKey)
|
||||||
|
) {
|
||||||
|
numberOfProperties++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var propertiesDelta = numberOfProperties - this.originalNumberOfProperties;
|
||||||
|
|
||||||
|
return this.tableViewModel
|
||||||
|
.updateCachedEntity(newEntity)
|
||||||
|
.then(() => {
|
||||||
|
if (!this.tryInsertNewHeaders(this.tableViewModel, newEntity)) {
|
||||||
|
this.tableViewModel.redrawTableThrottled();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// Selecting updated entity
|
||||||
|
this.tableViewModel.selected.removeAll();
|
||||||
|
this.tableViewModel.selected.push(newEntity);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public open() {
|
||||||
|
this.displayedAttributes(this.constructDisplayedAttributes(this.originEntity));
|
||||||
|
if (userContext.apiType === "Tables") {
|
||||||
|
this.originalDocument = TableEntityProcessor.convertEntitiesToDocuments(
|
||||||
|
[<Entities.ITableEntityForTablesAPI>this.originEntity],
|
||||||
|
this.tableViewModel.queryTablesTab.collection
|
||||||
|
)[0]; // TODO change for Cassandra
|
||||||
|
this.originalDocument.id = ko.observable<string>(this.originalDocument.id);
|
||||||
|
} else {
|
||||||
|
this.originalDocument = this.originEntity;
|
||||||
|
}
|
||||||
|
this.updateIsActionEnabled();
|
||||||
|
super.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructDisplayedAttributes(entity: Entities.ITableEntity): EntityPropertyViewModel[] {
|
||||||
|
var displayedAttributes: EntityPropertyViewModel[] = [];
|
||||||
|
const keys = Object.keys(entity);
|
||||||
|
keys &&
|
||||||
|
keys.forEach((key: string) => {
|
||||||
|
if (
|
||||||
|
key !== TableEntityProcessor.keyProperties.attachments &&
|
||||||
|
key !== TableEntityProcessor.keyProperties.etag &&
|
||||||
|
key !== TableEntityProcessor.keyProperties.resourceId &&
|
||||||
|
key !== TableEntityProcessor.keyProperties.self &&
|
||||||
|
(userContext.apiType !== "Cassandra" || key !== TableConstants.EntityKeyNames.RowKey)
|
||||||
|
) {
|
||||||
|
if (userContext.apiType === "Cassandra") {
|
||||||
|
const cassandraKeys = this.tableViewModel.queryTablesTab.collection.cassandraKeys.partitionKeys
|
||||||
|
.concat(this.tableViewModel.queryTablesTab.collection.cassandraKeys.clusteringKeys)
|
||||||
|
.map((key) => key.property);
|
||||||
|
var entityAttribute: Entities.ITableEntityAttribute = entity[key];
|
||||||
|
var entityAttributeType: string = entityAttribute.$;
|
||||||
|
var displayValue: any = this.getPropertyDisplayValue(entity, key, entityAttributeType);
|
||||||
|
var removable: boolean = false;
|
||||||
|
// TODO figure out validation story for blob and Inet so we can allow adding/editing them
|
||||||
|
const nonEditableType: boolean =
|
||||||
|
entityAttributeType === TableConstants.CassandraType.Blob ||
|
||||||
|
entityAttributeType === TableConstants.CassandraType.Inet;
|
||||||
|
|
||||||
|
displayedAttributes.push(
|
||||||
|
new EntityPropertyViewModel(
|
||||||
|
this,
|
||||||
|
key,
|
||||||
|
entityAttributeType,
|
||||||
|
displayValue,
|
||||||
|
/* namePlaceholder */ undefined,
|
||||||
|
/* valuePlaceholder */ undefined,
|
||||||
|
false,
|
||||||
|
/* default valid name */ true,
|
||||||
|
/* default valid value */ true,
|
||||||
|
/* isRequired */ false,
|
||||||
|
removable,
|
||||||
|
/*value editable*/ !_.contains<string>(cassandraKeys, key) && !nonEditableType
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
var entityAttribute: Entities.ITableEntityAttribute = entity[key];
|
||||||
|
var entityAttributeType: string = entityAttribute.$;
|
||||||
|
var displayValue: any = this.getPropertyDisplayValue(entity, key, entityAttributeType);
|
||||||
|
var editable: boolean = this.isAttributeEditable(key, entityAttributeType);
|
||||||
|
// As per VSO:189935, Binary properties are read-only, we still want to be able to remove them.
|
||||||
|
var removable: boolean = editable || entityAttributeType === TableConstants.TableType.Binary;
|
||||||
|
|
||||||
|
displayedAttributes.push(
|
||||||
|
new EntityPropertyViewModel(
|
||||||
|
this,
|
||||||
|
key,
|
||||||
|
entityAttributeType,
|
||||||
|
displayValue,
|
||||||
|
/* namePlaceholder */ undefined,
|
||||||
|
/* valuePlaceholder */ undefined,
|
||||||
|
editable,
|
||||||
|
/* default valid name */ true,
|
||||||
|
/* default valid value */ true,
|
||||||
|
/* isRequired */ false,
|
||||||
|
removable
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (userContext.apiType === "Cassandra") {
|
||||||
|
(<CassandraAPIDataClient>this.container.tableDataClient)
|
||||||
|
.getTableSchema(this.tableViewModel.queryTablesTab.collection)
|
||||||
|
.then((properties: CassandraTableKey[]) => {
|
||||||
|
properties &&
|
||||||
|
properties.forEach((property) => {
|
||||||
|
if (!_.contains(keys, property.property)) {
|
||||||
|
this.insertAttribute(property.property, property.type);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return displayedAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateEntity(displayedAttributes: EntityPropertyViewModel[]): Entities.ITableEntity {
|
||||||
|
var updatedEntity: any = {};
|
||||||
|
displayedAttributes &&
|
||||||
|
displayedAttributes.forEach((attribute: EntityPropertyViewModel) => {
|
||||||
|
if (attribute.name() && (userContext.apiType !== "Cassandra" || attribute.value() !== "")) {
|
||||||
|
var value = attribute.getPropertyValue();
|
||||||
|
var type = attribute.type();
|
||||||
|
if (type === TableConstants.TableType.Int64) {
|
||||||
|
value = Utilities.padLongWithZeros(value);
|
||||||
|
}
|
||||||
|
updatedEntity[attribute.name()] = {
|
||||||
|
_: value,
|
||||||
|
$: type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return updatedEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isAttributeEditable(attributeName: string, entityAttributeType: string) {
|
||||||
|
return !(
|
||||||
|
attributeName === TableConstants.EntityKeyNames.PartitionKey ||
|
||||||
|
attributeName === TableConstants.EntityKeyNames.RowKey ||
|
||||||
|
attributeName === TableConstants.EntityKeyNames.Timestamp ||
|
||||||
|
// As per VSO:189935, Making Binary properties read-only in Edit Entity dialog until we have a full story for it.
|
||||||
|
entityAttributeType === TableConstants.TableType.Binary
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private getPropertyDisplayValue(entity: Entities.ITableEntity, name: string, type: string): any {
|
||||||
|
var attribute: Entities.ITableEntityAttribute = entity[name];
|
||||||
|
var displayValue: any = attribute._;
|
||||||
|
var isBinary: boolean = type === TableConstants.TableType.Binary;
|
||||||
|
|
||||||
|
// Showing the value in base64 for binary properties since that is what the Azure Storage Client Library expects.
|
||||||
|
// This means that, even if the Azure Storage API returns a byte[] of binary content, it needs that same array
|
||||||
|
// *base64 - encoded * as the value for the updated property or the whole update operation will fail.
|
||||||
|
if (isBinary && displayValue && $.isArray(displayValue.data)) {
|
||||||
|
var bytes: number[] = displayValue.data;
|
||||||
|
displayValue = this.getBase64DisplayValue(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getBase64DisplayValue(bytes: number[]): string {
|
||||||
|
var displayValue: string = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var chars: string[] = bytes.map((byte: number) => String.fromCharCode(byte));
|
||||||
|
var toEncode: string = chars.join("");
|
||||||
|
displayValue = window.btoa(toEncode);
|
||||||
|
} catch (error) {
|
||||||
|
// Error
|
||||||
|
}
|
||||||
|
|
||||||
|
return displayValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
164
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
Normal file
164
src/Explorer/Panes/Tables/EntityPropertyViewModel.ts
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import * as ko from "knockout";
|
||||||
|
|
||||||
|
import * as DateTimeUtilities from "../../Tables/QueryBuilder/DateTimeUtilities";
|
||||||
|
import * as EntityPropertyNameValidator from "./Validators/EntityPropertyNameValidator";
|
||||||
|
import EntityPropertyValueValidator from "./Validators/EntityPropertyValueValidator";
|
||||||
|
import * as Constants from "../../Tables/Constants";
|
||||||
|
import * as Utilities from "../../Tables/Utilities";
|
||||||
|
import TableEntityPane from "./TableEntityPane";
|
||||||
|
|
||||||
|
export interface IValidationResult {
|
||||||
|
isInvalid: boolean;
|
||||||
|
help: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IActionEnabledDialog {
|
||||||
|
updateIsActionEnabled: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View model for an entity proprety
|
||||||
|
*/
|
||||||
|
export default class EntityPropertyViewModel {
|
||||||
|
/* Constants */
|
||||||
|
public static noTooltip = "";
|
||||||
|
// Maximum number of custom properties, see Azure Service Data Model
|
||||||
|
// At https://msdn.microsoft.com/library/azure/dd179338.aspx
|
||||||
|
public static maximumNumberOfProperties = 252;
|
||||||
|
|
||||||
|
// Labels
|
||||||
|
public closeButtonLabel: string = "Close"; // localize
|
||||||
|
|
||||||
|
/* Observables */
|
||||||
|
public name: ko.Observable<string>;
|
||||||
|
public type: ko.Observable<string>;
|
||||||
|
public value: ko.Observable<any>;
|
||||||
|
public inputType: ko.Computed<string>;
|
||||||
|
|
||||||
|
public nameTooltip: ko.Observable<string>;
|
||||||
|
public isInvalidName: ko.Observable<boolean>;
|
||||||
|
|
||||||
|
public valueTooltip: ko.Observable<string>;
|
||||||
|
public isInvalidValue: ko.Observable<boolean>;
|
||||||
|
|
||||||
|
public namePlaceholder: ko.Observable<string>;
|
||||||
|
public valuePlaceholder: ko.Observable<string>;
|
||||||
|
|
||||||
|
public hasFocus: ko.Observable<boolean>;
|
||||||
|
public valueHasFocus: ko.Observable<boolean>;
|
||||||
|
public isDateType: ko.Computed<boolean>;
|
||||||
|
|
||||||
|
public editable: boolean; // If a property's name or type is editable, these two are always the same regarding editability.
|
||||||
|
public valueEditable: boolean; // If a property's value is editable, could be different from name or type.
|
||||||
|
public removable: boolean; // If a property is removable, usually, PartitionKey, RowKey and TimeStamp (if applicable) are not removable.
|
||||||
|
public isRequired: boolean; // If a property's value is required, used to differentiate the place holder label.
|
||||||
|
public ignoreEmptyValue: boolean;
|
||||||
|
|
||||||
|
/* Members */
|
||||||
|
private tableEntityPane: TableEntityPane;
|
||||||
|
private _validator: EntityPropertyValueValidator;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
tableEntityPane: TableEntityPane,
|
||||||
|
name: string,
|
||||||
|
type: string,
|
||||||
|
value: any,
|
||||||
|
namePlaceholder: string = "",
|
||||||
|
valuePlaceholder: string = "",
|
||||||
|
editable: boolean = false,
|
||||||
|
defaultValidName: boolean = true,
|
||||||
|
defaultValidValue: boolean = false,
|
||||||
|
isRequired: boolean = false,
|
||||||
|
removable: boolean = editable,
|
||||||
|
valueEditable: boolean = editable,
|
||||||
|
ignoreEmptyValue: boolean = false
|
||||||
|
) {
|
||||||
|
this.name = ko.observable<string>(name);
|
||||||
|
this.type = ko.observable<string>(type);
|
||||||
|
this.isDateType = ko.pureComputed<boolean>(() => this.type() === Constants.TableType.DateTime);
|
||||||
|
if (this.isDateType()) {
|
||||||
|
value = value ? DateTimeUtilities.getLocalDateTime(value) : value;
|
||||||
|
}
|
||||||
|
this.value = ko.observable(value);
|
||||||
|
this.inputType = ko.pureComputed<string>(() => {
|
||||||
|
if (!this.valueHasFocus() && !this.value() && this.isDateType()) {
|
||||||
|
return Constants.InputType.Text;
|
||||||
|
}
|
||||||
|
return Utilities.getInputTypeFromDisplayedName(this.type());
|
||||||
|
});
|
||||||
|
|
||||||
|
this.namePlaceholder = ko.observable<string>(namePlaceholder);
|
||||||
|
this.valuePlaceholder = ko.observable<string>(valuePlaceholder);
|
||||||
|
|
||||||
|
this.editable = editable;
|
||||||
|
this.isRequired = isRequired;
|
||||||
|
this.removable = removable;
|
||||||
|
this.valueEditable = valueEditable;
|
||||||
|
|
||||||
|
this._validator = new EntityPropertyValueValidator(isRequired);
|
||||||
|
|
||||||
|
this.tableEntityPane = tableEntityPane;
|
||||||
|
|
||||||
|
this.nameTooltip = ko.observable<string>(EntityPropertyViewModel.noTooltip);
|
||||||
|
this.isInvalidName = ko.observable<boolean>(!defaultValidName);
|
||||||
|
this.name.subscribe((name: string) => this.validateName(name));
|
||||||
|
if (!defaultValidName) {
|
||||||
|
this.validateName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.valueTooltip = ko.observable<string>(EntityPropertyViewModel.noTooltip);
|
||||||
|
this.isInvalidValue = ko.observable<boolean>(!defaultValidValue);
|
||||||
|
this.value.subscribe((value: string) => this.validateValue(value, this.type()));
|
||||||
|
if (!defaultValidValue) {
|
||||||
|
this.validateValue(value, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.type.subscribe((type: string) => this.validateValue(this.value(), type));
|
||||||
|
|
||||||
|
this.hasFocus = ko.observable<boolean>(false);
|
||||||
|
this.valueHasFocus = ko.observable<boolean>(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Javascript value of the entity property based on its EDM type.
|
||||||
|
*/
|
||||||
|
public getPropertyValue(): any {
|
||||||
|
var value: string = this.value();
|
||||||
|
if (this.type() === Constants.TableType.DateTime) {
|
||||||
|
value = DateTimeUtilities.getUTCDateTime(value);
|
||||||
|
}
|
||||||
|
return this._validator.parseValue(value, this.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateName(name: string): void {
|
||||||
|
var result: IValidationResult = this.isInvalidNameInput(name);
|
||||||
|
|
||||||
|
this.isInvalidName(result.isInvalid);
|
||||||
|
this.nameTooltip(result.help);
|
||||||
|
this.namePlaceholder(result.help);
|
||||||
|
this.tableEntityPane.updateIsActionEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
private validateValue(value: string, type: string): void {
|
||||||
|
var result: IValidationResult = this.isInvalidValueInput(value, type);
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isInvalidValue(result.isInvalid);
|
||||||
|
this.valueTooltip(result.help);
|
||||||
|
this.valuePlaceholder(result.help);
|
||||||
|
this.tableEntityPane.updateIsActionEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
private isInvalidNameInput(name: string): IValidationResult {
|
||||||
|
return EntityPropertyNameValidator.validate(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private isInvalidValueInput(value: string, type: string): IValidationResult {
|
||||||
|
if (this.ignoreEmptyValue && this.value() === "") {
|
||||||
|
return { isInvalid: false, help: "" };
|
||||||
|
}
|
||||||
|
return this._validator.validate(value, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
190
src/Explorer/Panes/Tables/TableAddEntityPane.html
Normal file
190
src/Explorer/Panes/Tables/TableAddEntityPane.html
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
<div data-bind="visible: visible">
|
||||||
|
<div
|
||||||
|
class="contextual-pane-out"
|
||||||
|
data-bind="
|
||||||
|
click: cancel,
|
||||||
|
clickBubble: false"
|
||||||
|
></div>
|
||||||
|
<div class="contextual-pane" style="width: 700px" id="addtableentitypane">
|
||||||
|
<!-- Add table entity form - Start -->
|
||||||
|
<div
|
||||||
|
class="contextual-pane-in"
|
||||||
|
data-bind="
|
||||||
|
visible: !isEditing()"
|
||||||
|
>
|
||||||
|
<form
|
||||||
|
class="paneContentContainer"
|
||||||
|
data-bind="
|
||||||
|
submit: submit"
|
||||||
|
>
|
||||||
|
<!-- Add table entity header - Start -->
|
||||||
|
<div class="firstdivbg headerline">
|
||||||
|
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||||
|
<div
|
||||||
|
id="closeAddEntityPane"
|
||||||
|
class="closeImg"
|
||||||
|
role="button"
|
||||||
|
aria-label="Close pane"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="
|
||||||
|
click: cancel, event: { keydown: onCloseKeyPress }"
|
||||||
|
>
|
||||||
|
<img src="../../../../images/close-black.svg" title="Close" alt="Close" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Add table entity header - End -->
|
||||||
|
<div class="tableParamContent paneContentContainer">
|
||||||
|
<div class="entity-table">
|
||||||
|
<div class="entity-table-row">
|
||||||
|
<div class="entity-table-cell entity-table-property-header" data-bind="text: attributeNameLabel"></div>
|
||||||
|
<div class="entity-table-cell entity-table-type-header" data-bind="text: dataTypeLabel"></div>
|
||||||
|
<div class="entity-table-cell entity-table-value-header" data-bind="text: attributeValueLabel"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="entity-table-scroll-box" id="addEntityScroll">
|
||||||
|
<div class="entity-table" data-bind="foreach: displayedAttributes">
|
||||||
|
<div class="entity-table-row">
|
||||||
|
<div class="entity-table-cell entity-table-property-column">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="entity-table-field entity-table-property-column"
|
||||||
|
required
|
||||||
|
data-bind="
|
||||||
|
textInput: name,
|
||||||
|
attr: { title: nameTooltip, placeholder: namePlaceholder, 'aria-label': 'property name' },
|
||||||
|
css: { 'invalid-field': isInvalidName },
|
||||||
|
readOnly: !editable,
|
||||||
|
hasFocus: hasFocus"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="entity-table-cell entity-table-type-column">
|
||||||
|
<select
|
||||||
|
class="entity-table-field"
|
||||||
|
data-bind="
|
||||||
|
options: $parent.edmTypes,
|
||||||
|
optionsAfterRender: $parent.setOptionDisable,
|
||||||
|
value: type,
|
||||||
|
attr: { 'aria-label': 'type' },
|
||||||
|
enable: editable,
|
||||||
|
readOnly: !editable"
|
||||||
|
></select>
|
||||||
|
</div>
|
||||||
|
<!-- ko ifnot: isDateType -->
|
||||||
|
<div class="entity-table-cell entity-table-value-column">
|
||||||
|
<input
|
||||||
|
class="entity-table-field"
|
||||||
|
id="addTableEntityValue"
|
||||||
|
step="1"
|
||||||
|
data-bind="
|
||||||
|
textInput: value,
|
||||||
|
attr: { title: valueTooltip, placeholder: valuePlaceholder, type: inputType, 'aria-label': 'value' },
|
||||||
|
css: { 'invalid-field': isInvalidValue },
|
||||||
|
readOnly: !valueEditable"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<!-- ko if: isDateType -->
|
||||||
|
<div class="entity-table-cell entity-table-value-column">
|
||||||
|
<input
|
||||||
|
class="entity-table-field"
|
||||||
|
step="1"
|
||||||
|
data-bind="
|
||||||
|
value: value,
|
||||||
|
attr: { title: valueTooltip, placeholder: valuePlaceholder, type: inputType },
|
||||||
|
css: { 'invalid-field': isInvalidValue },
|
||||||
|
readOnly: !valueEditable,
|
||||||
|
hasFocus: valueHasFocus"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<div class="entity-table-cell entity-table-action-column" data-bind="if: removable || valueEditable">
|
||||||
|
<span
|
||||||
|
class="entity-Edit-Cancel"
|
||||||
|
title="Edit property"
|
||||||
|
role="button"
|
||||||
|
aria-label="Edit property"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="click: $parent.editAttribute.bind($data, $index()), visible: valueEditable, event: { keydown: $parent.onEditPropertyKeyDown.bind($data, $index()) }"
|
||||||
|
>
|
||||||
|
<img class="entity-Editor-Cancel-Img" src="/Edit_entity.svg" alt="Edit" />
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="entity-Edit-Cancel"
|
||||||
|
title="Delete property"
|
||||||
|
role="button"
|
||||||
|
aria-label="Delete property"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="click: $parent.removeAttribute.bind($data, $index()), visible: removable, event: { keydown: $parent.onDeletePropertyKeyDown.bind($data, $index()) }"
|
||||||
|
>
|
||||||
|
<img class="entity-Editor-Cancel-Img" src="/delete.svg" alt="Cancel" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="entity-table addProperty">
|
||||||
|
<div class="entity-table-row">
|
||||||
|
<div class="entity-table-cell">
|
||||||
|
<span
|
||||||
|
class="commandButton"
|
||||||
|
id="addProperty"
|
||||||
|
role="button"
|
||||||
|
aria-label="Add property"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="visible: canAdd, click: insertAttribute, event: { keydown: onAddPropertyKeyDown }"
|
||||||
|
autofocus
|
||||||
|
>
|
||||||
|
<img class="addPropertyImg" src="/Add-property.svg" alt="Insert attribute" />
|
||||||
|
<span data-bind="text: addButtonLabel"> </span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="paneFooter">
|
||||||
|
<div class="leftpanel-okbut">
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
class="btncreatecoll1"
|
||||||
|
data-bind="value: submitButtonText, event: { keydown: onSubmitKeyPress }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<!-- Add table entity form - End -->
|
||||||
|
<!-- Add table entity editor - Start -->
|
||||||
|
<div id="editor-panel-addEntity" data-bind="visible: isEditing()" style="display: none">
|
||||||
|
<div data-bind="with: editingProperty()">
|
||||||
|
<!-- Add table entity editor header - Start -->
|
||||||
|
<div class="firstdivbg headerline">
|
||||||
|
<span
|
||||||
|
class="backBtn"
|
||||||
|
aria-label="Back"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="
|
||||||
|
click: $parent.finishEditingAttribute, event: { keydown: $parent.onBackButtonKeyDown }"
|
||||||
|
>
|
||||||
|
<img src="/RevertBack.svg" alt="BackIcon" />
|
||||||
|
</span>
|
||||||
|
<span class="edit-value-text" data-bind="text: name"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Add table entity editor header - End -->
|
||||||
|
<div class="seconddivbg paddingspan2">
|
||||||
|
<textarea
|
||||||
|
class="entity-editor-expanded"
|
||||||
|
id="textAreaEditProperty"
|
||||||
|
tabindex="0"
|
||||||
|
rows="21"
|
||||||
|
data-bind="value: value, attr: { 'aria-label': name }"
|
||||||
|
style="width: 95%"
|
||||||
|
autofocus
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Add table entity editor - End -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
187
src/Explorer/Panes/Tables/TableEditEntityPane.html
Normal file
187
src/Explorer/Panes/Tables/TableEditEntityPane.html
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<div data-bind="visible: visible">
|
||||||
|
<div
|
||||||
|
class="contextual-pane-out"
|
||||||
|
data-bind="
|
||||||
|
click: cancel,
|
||||||
|
clickBubble: false"
|
||||||
|
></div>
|
||||||
|
<div class="contextual-pane" style="width: 700px" id="edittableentitypane">
|
||||||
|
<!-- Edit table entity form - Start -->
|
||||||
|
<div
|
||||||
|
class="contextual-pane-in"
|
||||||
|
data-bind="
|
||||||
|
visible: !isEditing()"
|
||||||
|
>
|
||||||
|
<form
|
||||||
|
class="paneContentContainer"
|
||||||
|
data-bind="
|
||||||
|
submit: submit"
|
||||||
|
>
|
||||||
|
<!-- Edit table entity header - Start -->
|
||||||
|
<div class="firstdivbg headerline">
|
||||||
|
<span role="heading" aria-level="2" data-bind="text: title"></span>
|
||||||
|
<div
|
||||||
|
class="closeImg"
|
||||||
|
role="button"
|
||||||
|
aria-label="Close pane"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="
|
||||||
|
click: cancel, event: { keydown: onCloseKeyPress }"
|
||||||
|
>
|
||||||
|
<img src="../../../../images/close-black.svg" title="Close" alt="Close" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Edit table entity header - End -->
|
||||||
|
<div class="tableParamContent paneContentContainer">
|
||||||
|
<div class="entity-table">
|
||||||
|
<div class="entity-table-row">
|
||||||
|
<div class="entity-table-cell entity-table-property-header" data-bind="text: attributeNameLabel"></div>
|
||||||
|
<div class="entity-table-cell entity-table-type-header" data-bind="text: dataTypeLabel"></div>
|
||||||
|
<div class="entity-table-cell entity-table-value-header" data-bind="text: attributeValueLabel"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="entity-table-scroll-box" id="editEntityScroll">
|
||||||
|
<div class="entity-table" data-bind="foreach: displayedAttributes">
|
||||||
|
<div class="entity-table-row">
|
||||||
|
<div class="entity-table-cell entity-table-property-column">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="entity-table-field entity-table-property-column"
|
||||||
|
required
|
||||||
|
data-bind="
|
||||||
|
textInput: name,
|
||||||
|
attr: { title: nameTooltip, placeholder: namePlaceholder, 'aria-label': 'property name' },
|
||||||
|
css: { 'invalid-field': isInvalidName },
|
||||||
|
readOnly: !editable,
|
||||||
|
hasFocus: hasFocus"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="entity-table-cell entity-table-type-column">
|
||||||
|
<select
|
||||||
|
class="entity-table-field"
|
||||||
|
data-bind="
|
||||||
|
options: $parent.edmTypes,
|
||||||
|
optionsAfterRender: $parent.setOptionDisable,
|
||||||
|
value: type,
|
||||||
|
attr: { 'aria-label': 'type' },
|
||||||
|
enable: editable,
|
||||||
|
readOnly: !editable"
|
||||||
|
></select>
|
||||||
|
</div>
|
||||||
|
<!-- ko ifnot: isDateType -->
|
||||||
|
<div class="entity-table-cell entity-table-value-column">
|
||||||
|
<input
|
||||||
|
class="entity-table-field"
|
||||||
|
step="1"
|
||||||
|
data-bind="
|
||||||
|
textInput: value,
|
||||||
|
attr: { title: valueTooltip, placeholder: valuePlaceholder, type: inputType, 'aria-label': 'value' },
|
||||||
|
css: { 'invalid-field': isInvalidValue },
|
||||||
|
readOnly: !valueEditable"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<!-- ko if: isDateType -->
|
||||||
|
<div class="entity-table-cell entity-table-value-column">
|
||||||
|
<input
|
||||||
|
class="entity-table-field"
|
||||||
|
step="1"
|
||||||
|
data-bind="
|
||||||
|
value: value,
|
||||||
|
attr: { title: valueTooltip, placeholder: valuePlaceholder, type: inputType, 'aria-label': 'value' },
|
||||||
|
css: { 'invalid-field': isInvalidValue },
|
||||||
|
readOnly: !valueEditable,
|
||||||
|
hasFocus: valueHasFocus"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- /ko -->
|
||||||
|
<div class="entity-table-cell entity-table-action-column" data-bind="if: removable || valueEditable">
|
||||||
|
<span
|
||||||
|
class="entity-Edit-Cancel"
|
||||||
|
role="button"
|
||||||
|
aria-label="Edit property"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="click: $parent.editAttribute.bind($data, $index()), visible: valueEditable, event: { keydown: $parent.onEditPropertyKeyDown.bind($data, $index()) }"
|
||||||
|
title="Edit property"
|
||||||
|
>
|
||||||
|
<img class="entity-Editor-Cancel-Img" src="/Edit_entity.svg" alt="Edit attribute" />
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="entity-Edit-Cancel"
|
||||||
|
role="button"
|
||||||
|
aria-label="Delete property"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="click: $parent.removeAttribute.bind($data, $index()), visible: removable, event: { keydown: $parent.onDeletePropertyKeyDown.bind($data, $index()) }"
|
||||||
|
title="Delete property"
|
||||||
|
>
|
||||||
|
<img class="entity-Editor-Cancel-Img" src="/delete.svg" alt="Remove attribute" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="entity-table addProperty">
|
||||||
|
<div class="entity-table-row">
|
||||||
|
<div class="entity-table-cell">
|
||||||
|
<span
|
||||||
|
class="commandButton"
|
||||||
|
role="button"
|
||||||
|
aria-label="Add property"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="visible: canAdd, click: insertAttribute, event: { keydown: onAddPropertyKeyDown }"
|
||||||
|
autofocus
|
||||||
|
>
|
||||||
|
<img class="addPropertyImg" src="/Add-property.svg" alt="Add attribute" />
|
||||||
|
<span data-bind="text: addButtonLabel"> </span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="paneFooter">
|
||||||
|
<div class="leftpanel-okbut">
|
||||||
|
<input
|
||||||
|
type="submit"
|
||||||
|
value="Update Entity"
|
||||||
|
class="btncreatecoll1"
|
||||||
|
data-bind="value: submitButtonText, event: { keydown: onSubmitKeyPress }"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<!-- Edit table entity form - End -->
|
||||||
|
<!-- Edit table entity editor - Start -->
|
||||||
|
<div id="editor-panel-editEntity" data-bind="visible: isEditing()" style="display: none">
|
||||||
|
<div data-bind="with: editingProperty()">
|
||||||
|
<!-- Edit table entity editor header - Start -->
|
||||||
|
<div class="firstdivbg headerline">
|
||||||
|
<span
|
||||||
|
class="backBtn"
|
||||||
|
aria-label="Back"
|
||||||
|
role="button"
|
||||||
|
tabindex="0"
|
||||||
|
data-bind="
|
||||||
|
click: $parent.finishEditingAttribute, event: { keydown: $parent.onBackButtonKeyDown }"
|
||||||
|
>
|
||||||
|
<img src="/RevertBack.svg" alt="BackIcon" />
|
||||||
|
</span>
|
||||||
|
<span class="edit-value-text" data-bind="text: name"></span>
|
||||||
|
</div>
|
||||||
|
<!-- Edit table entity editor header - End -->
|
||||||
|
<div class="seconddivbg paddingspan2">
|
||||||
|
<textarea
|
||||||
|
class="entity-editor-expanded"
|
||||||
|
id="editor-area"
|
||||||
|
tabindex="0"
|
||||||
|
rows="21"
|
||||||
|
data-bind="value: value, attr: { 'aria-label': name }"
|
||||||
|
autofocus
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Edit table entity editor - End -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
279
src/Explorer/Panes/Tables/TableEntityPane.ts
Normal file
279
src/Explorer/Panes/Tables/TableEntityPane.ts
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
import * as ko from "knockout";
|
||||||
|
import _ from "underscore";
|
||||||
|
import { KeyCodes } from "../../../Common/Constants";
|
||||||
|
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||||
|
import { userContext } from "../../../UserContext";
|
||||||
|
import * as TableConstants from "../../Tables/Constants";
|
||||||
|
import * as DataTableUtilities from "../../Tables/DataTable/DataTableUtilities";
|
||||||
|
import TableEntityListViewModel from "../../Tables/DataTable/TableEntityListViewModel";
|
||||||
|
import * as Entities from "../../Tables/Entities";
|
||||||
|
import * as TableEntityProcessor from "../../Tables/TableEntityProcessor";
|
||||||
|
import * as Utilities from "../../Tables/Utilities";
|
||||||
|
import { ContextualPaneBase } from "../ContextualPaneBase";
|
||||||
|
import EntityPropertyViewModel from "./EntityPropertyViewModel";
|
||||||
|
|
||||||
|
// Class with variables and functions that are common to both adding and editing entities
|
||||||
|
export default abstract class TableEntityPane extends ContextualPaneBase {
|
||||||
|
protected static requiredFieldsForTablesAPI: string[] = [
|
||||||
|
TableConstants.EntityKeyNames.PartitionKey,
|
||||||
|
TableConstants.EntityKeyNames.RowKey,
|
||||||
|
];
|
||||||
|
|
||||||
|
/* Labels */
|
||||||
|
public attributeNameLabel = "Property Name"; // localize
|
||||||
|
public dataTypeLabel = "Type"; // localize
|
||||||
|
public attributeValueLabel = "Value"; // localize
|
||||||
|
|
||||||
|
/* Controls */
|
||||||
|
public removeButtonLabel = "Remove"; // localize
|
||||||
|
public editButtonLabel = "Edit"; // localize
|
||||||
|
public addButtonLabel = "Add Property"; // localize
|
||||||
|
|
||||||
|
public edmTypes: ko.ObservableArray<string> = ko.observableArray([
|
||||||
|
TableConstants.TableType.String,
|
||||||
|
TableConstants.TableType.Boolean,
|
||||||
|
TableConstants.TableType.Binary,
|
||||||
|
TableConstants.TableType.DateTime,
|
||||||
|
TableConstants.TableType.Double,
|
||||||
|
TableConstants.TableType.Guid,
|
||||||
|
TableConstants.TableType.Int32,
|
||||||
|
TableConstants.TableType.Int64,
|
||||||
|
]);
|
||||||
|
|
||||||
|
public canAdd: ko.Computed<boolean>;
|
||||||
|
public canApply: ko.Observable<boolean>;
|
||||||
|
public displayedAttributes = ko.observableArray<EntityPropertyViewModel>();
|
||||||
|
public editingProperty = ko.observable<EntityPropertyViewModel>();
|
||||||
|
public isEditing = ko.observable<boolean>(false);
|
||||||
|
public submitButtonText = ko.observable<string>();
|
||||||
|
|
||||||
|
public tableViewModel: TableEntityListViewModel;
|
||||||
|
|
||||||
|
protected scrollId: ko.Observable<string>;
|
||||||
|
|
||||||
|
constructor(options: ViewModels.PaneOptions) {
|
||||||
|
super(options);
|
||||||
|
if (userContext.apiType === "Cassandra") {
|
||||||
|
this.edmTypes([
|
||||||
|
TableConstants.CassandraType.Text,
|
||||||
|
TableConstants.CassandraType.Ascii,
|
||||||
|
TableConstants.CassandraType.Bigint,
|
||||||
|
TableConstants.CassandraType.Blob,
|
||||||
|
TableConstants.CassandraType.Boolean,
|
||||||
|
TableConstants.CassandraType.Decimal,
|
||||||
|
TableConstants.CassandraType.Double,
|
||||||
|
TableConstants.CassandraType.Float,
|
||||||
|
TableConstants.CassandraType.Int,
|
||||||
|
TableConstants.CassandraType.Uuid,
|
||||||
|
TableConstants.CassandraType.Varchar,
|
||||||
|
TableConstants.CassandraType.Varint,
|
||||||
|
TableConstants.CassandraType.Inet,
|
||||||
|
TableConstants.CassandraType.Smallint,
|
||||||
|
TableConstants.CassandraType.Tinyint,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.canAdd = ko.computed<boolean>(() => {
|
||||||
|
// Cassandra can't add since the schema can't be changed once created
|
||||||
|
if (userContext.apiType === "Cassandra") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Adding '2' to the maximum to take into account PartitionKey and RowKey
|
||||||
|
return this.displayedAttributes().length < EntityPropertyViewModel.maximumNumberOfProperties + 2;
|
||||||
|
});
|
||||||
|
this.canApply = ko.observable<boolean>(true);
|
||||||
|
this.editingProperty(this.displayedAttributes()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeAttribute = (index: number, data: any): void => {
|
||||||
|
this.displayedAttributes.splice(index, 1);
|
||||||
|
this.updateIsActionEnabled();
|
||||||
|
document.getElementById("addProperty").focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
public editAttribute = (index: number, data: EntityPropertyViewModel): void => {
|
||||||
|
this.editingProperty(data);
|
||||||
|
this.isEditing(true);
|
||||||
|
document.getElementById("textAreaEditProperty").focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
public finishEditingAttribute = (): void => {
|
||||||
|
this.isEditing(false);
|
||||||
|
this.editingProperty(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
public onKeyUp = (data: any, event: KeyboardEvent): boolean => {
|
||||||
|
var handled: boolean = Utilities.onEsc(event, ($sourceElement: JQuery) => {
|
||||||
|
this.finishEditingAttribute();
|
||||||
|
});
|
||||||
|
|
||||||
|
return !handled;
|
||||||
|
};
|
||||||
|
|
||||||
|
public onAddPropertyKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||||
|
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||||
|
this.insertAttribute();
|
||||||
|
event.stopPropagation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
public onEditPropertyKeyDown = (
|
||||||
|
index: number,
|
||||||
|
data: EntityPropertyViewModel,
|
||||||
|
event: KeyboardEvent,
|
||||||
|
source: any
|
||||||
|
): boolean => {
|
||||||
|
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||||
|
this.editAttribute(index, data);
|
||||||
|
event.stopPropagation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
public onDeletePropertyKeyDown = (
|
||||||
|
index: number,
|
||||||
|
data: EntityPropertyViewModel,
|
||||||
|
event: KeyboardEvent,
|
||||||
|
source: any
|
||||||
|
): boolean => {
|
||||||
|
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||||
|
this.removeAttribute(index, data);
|
||||||
|
event.stopPropagation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
public onBackButtonKeyDown = (source: any, event: KeyboardEvent): boolean => {
|
||||||
|
if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
|
||||||
|
this.finishEditingAttribute();
|
||||||
|
event.stopPropagation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
public insertAttribute = (name?: string, type?: string): void => {
|
||||||
|
let entityProperty: EntityPropertyViewModel;
|
||||||
|
if (!!name && !!type && userContext.apiType === "Cassandra") {
|
||||||
|
// TODO figure out validation story for blob and Inet so we can allow adding/editing them
|
||||||
|
const nonEditableType: boolean =
|
||||||
|
type === TableConstants.CassandraType.Blob || type === TableConstants.CassandraType.Inet;
|
||||||
|
entityProperty = new EntityPropertyViewModel(
|
||||||
|
this,
|
||||||
|
name,
|
||||||
|
type,
|
||||||
|
"", // default to empty string
|
||||||
|
/* namePlaceholder */ undefined,
|
||||||
|
/* valuePlaceholder */ undefined,
|
||||||
|
/* editable */ false,
|
||||||
|
/* default valid name */ false,
|
||||||
|
/* default valid value */ true,
|
||||||
|
/* isRequired */ false,
|
||||||
|
/* removable */ false,
|
||||||
|
/*value editable*/ !nonEditableType
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
entityProperty = new EntityPropertyViewModel(
|
||||||
|
this,
|
||||||
|
"",
|
||||||
|
this.edmTypes()[0], // default to the first Edm type: 'string'
|
||||||
|
"", // default to empty string
|
||||||
|
/* namePlaceholder */ undefined,
|
||||||
|
/* valuePlaceholder */ undefined,
|
||||||
|
/* editable */ true,
|
||||||
|
/* default valid name */ false,
|
||||||
|
/* default valid value */ true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayedAttributes.push(entityProperty);
|
||||||
|
this.updateIsActionEnabled();
|
||||||
|
this.scrollToBottom();
|
||||||
|
|
||||||
|
entityProperty.hasFocus(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
public updateIsActionEnabled(needRequiredFields: boolean = true): void {
|
||||||
|
var properties: EntityPropertyViewModel[] = this.displayedAttributes() || [];
|
||||||
|
var disable: boolean = _.some(properties, (property: EntityPropertyViewModel) => {
|
||||||
|
return property.isInvalidName() || property.isInvalidValue();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.canApply(!disable);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected entityFromAttributes(displayedAttributes: EntityPropertyViewModel[]): Entities.ITableEntity {
|
||||||
|
var entity: any = {};
|
||||||
|
|
||||||
|
displayedAttributes &&
|
||||||
|
displayedAttributes.forEach((attribute: EntityPropertyViewModel) => {
|
||||||
|
if (attribute.name() && (attribute.value() !== "" || attribute.isRequired)) {
|
||||||
|
var value = attribute.getPropertyValue();
|
||||||
|
var type = attribute.type();
|
||||||
|
if (type === TableConstants.TableType.Int64) {
|
||||||
|
value = Utilities.padLongWithZeros(value);
|
||||||
|
}
|
||||||
|
entity[attribute.name()] = {
|
||||||
|
_: value,
|
||||||
|
$: type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removing Binary from Add Entity dialog until we have a full story for it.
|
||||||
|
protected setOptionDisable(option: Node, value: string): void {
|
||||||
|
ko.applyBindingsToNode(option, { disable: value === TableConstants.TableType.Binary }, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the updated entity to see if there are any new attributes that old headers don't have.
|
||||||
|
* In this case, add these attributes names as new headers.
|
||||||
|
* Remarks: adding new headers will automatically trigger table redraw.
|
||||||
|
*/
|
||||||
|
protected tryInsertNewHeaders(viewModel: TableEntityListViewModel, newEntity: Entities.ITableEntity): boolean {
|
||||||
|
var newHeaders: string[] = [];
|
||||||
|
const keys = Object.keys(newEntity);
|
||||||
|
keys &&
|
||||||
|
keys.forEach((key: string) => {
|
||||||
|
if (
|
||||||
|
!_.contains(viewModel.headers, key) &&
|
||||||
|
key !== TableEntityProcessor.keyProperties.attachments &&
|
||||||
|
key !== TableEntityProcessor.keyProperties.etag &&
|
||||||
|
key !== TableEntityProcessor.keyProperties.resourceId &&
|
||||||
|
key !== TableEntityProcessor.keyProperties.self &&
|
||||||
|
(userContext.apiType !== "Cassandra" || key !== TableConstants.EntityKeyNames.RowKey)
|
||||||
|
) {
|
||||||
|
newHeaders.push(key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var newHeadersInserted: boolean = false;
|
||||||
|
if (newHeaders.length) {
|
||||||
|
if (!DataTableUtilities.checkForDefaultHeader(viewModel.headers)) {
|
||||||
|
newHeaders = viewModel.headers.concat(newHeaders);
|
||||||
|
}
|
||||||
|
viewModel.updateHeaders(newHeaders, /* notifyColumnChanges */ true, /* enablePrompt */ false);
|
||||||
|
newHeadersInserted = true;
|
||||||
|
}
|
||||||
|
return newHeadersInserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected scrollToBottom(): void {
|
||||||
|
var scrollBox = document.getElementById(this.scrollId());
|
||||||
|
var isScrolledToBottom = scrollBox.scrollHeight - scrollBox.clientHeight <= scrollBox.scrollHeight + 1;
|
||||||
|
if (isScrolledToBottom) {
|
||||||
|
scrollBox.scrollTop = scrollBox.scrollHeight - scrollBox.clientHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -51,7 +51,7 @@ class KeyValidator implements ValueValidator {
|
|||||||
class BooleanValueValidator extends ValueValidator {
|
class BooleanValueValidator extends ValueValidator {
|
||||||
private detailedHelp = "Enter true or false."; // localize
|
private detailedHelp = "Enter true or false."; // localize
|
||||||
|
|
||||||
public override validate(value: string): IValidationResult {
|
public validate(value: string): IValidationResult {
|
||||||
var success: boolean = false;
|
var success: boolean = false;
|
||||||
var help: string = noHelp;
|
var help: string = noHelp;
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ class BooleanValueValidator extends ValueValidator {
|
|||||||
return { isInvalid: !success, help: help };
|
return { isInvalid: !success, help: help };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override parseValue(value: string): boolean {
|
public parseValue(value: string): boolean {
|
||||||
// OData seems to require lowercase boolean values, see http://www.odata.org/documentation/odata-version-2-0/overview/
|
// OData seems to require lowercase boolean values, see http://www.odata.org/documentation/odata-version-2-0/overview/
|
||||||
return value.toString().toLowerCase() === "true";
|
return value.toString().toLowerCase() === "true";
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ class BooleanValueValidator extends ValueValidator {
|
|||||||
class DateTimeValueValidator extends ValueValidator {
|
class DateTimeValueValidator extends ValueValidator {
|
||||||
private detailedHelp = "Enter a date and time."; // localize
|
private detailedHelp = "Enter a date and time."; // localize
|
||||||
|
|
||||||
public override validate(value: string): IValidationResult {
|
public validate(value: string): IValidationResult {
|
||||||
var success: boolean = false;
|
var success: boolean = false;
|
||||||
var help: string = noHelp;
|
var help: string = noHelp;
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ class DateTimeValueValidator extends ValueValidator {
|
|||||||
return { isInvalid: !success, help: help };
|
return { isInvalid: !success, help: help };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override parseValue(value: string): Date {
|
public parseValue(value: string): Date {
|
||||||
var millisecondTime = Date.parse(value);
|
var millisecondTime = Date.parse(value);
|
||||||
var parsed: Date = new Date(millisecondTime);
|
var parsed: Date = new Date(millisecondTime);
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ class DateTimeValueValidator extends ValueValidator {
|
|||||||
class DoubleValueValidator extends ValueValidator {
|
class DoubleValueValidator extends ValueValidator {
|
||||||
private detailedHelp = "Enter a 64-bit floating point value."; // localize
|
private detailedHelp = "Enter a 64-bit floating point value."; // localize
|
||||||
|
|
||||||
public override validate(value: string): IValidationResult {
|
public validate(value: string): IValidationResult {
|
||||||
var success: boolean = false;
|
var success: boolean = false;
|
||||||
var help: string = noHelp;
|
var help: string = noHelp;
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ class DoubleValueValidator extends ValueValidator {
|
|||||||
return { isInvalid: !success, help: help };
|
return { isInvalid: !success, help: help };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override parseValue(value: string): number {
|
public parseValue(value: string): number {
|
||||||
return parseFloat(value);
|
return parseFloat(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ class DoubleValueValidator extends ValueValidator {
|
|||||||
class GuidValueValidator extends ValueValidator {
|
class GuidValueValidator extends ValueValidator {
|
||||||
private detailedHelp = "Enter a 16-byte (128-bit) GUID value."; // localize
|
private detailedHelp = "Enter a 16-byte (128-bit) GUID value."; // localize
|
||||||
|
|
||||||
public override validate(value: string): IValidationResult {
|
public validate(value: string): IValidationResult {
|
||||||
var success: boolean = false;
|
var success: boolean = false;
|
||||||
var help: string = noHelp;
|
var help: string = noHelp;
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ class IntegerValueValidator extends ValueValidator {
|
|||||||
this.isInt64 = isInt64;
|
this.isInt64 = isInt64;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override validate(value: string): IValidationResult {
|
public validate(value: string): IValidationResult {
|
||||||
var success: boolean = false;
|
var success: boolean = false;
|
||||||
var help: string = noHelp;
|
var help: string = noHelp;
|
||||||
|
|
||||||
@@ -180,7 +180,7 @@ class IntegerValueValidator extends ValueValidator {
|
|||||||
return { isInvalid: !success, help: help };
|
return { isInvalid: !success, help: help };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override parseValue(value: string): number {
|
public parseValue(value: string): number {
|
||||||
return parseInt(value, 10);
|
return parseInt(value, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +198,7 @@ class StringValidator extends ValueValidator {
|
|||||||
this.isRequired = isRequired;
|
this.isRequired = isRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override validate(value: string): IValidationResult {
|
public validate(value: string): IValidationResult {
|
||||||
var help: string = this.isRequired ? this.isRequiredHelp : this.detailedHelp;
|
var help: string = this.isRequired ? this.isRequiredHelp : this.detailedHelp;
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
return { isInvalid: false, help: help };
|
return { isInvalid: false, help: help };
|
||||||
@@ -219,7 +219,7 @@ class StringValidator extends ValueValidator {
|
|||||||
return { isInvalid: !success, help: help };
|
return { isInvalid: !success, help: help };
|
||||||
}
|
}
|
||||||
|
|
||||||
public override parseValue(value: string): string {
|
public parseValue(value: string): string {
|
||||||
return String(value); // Ensure value is converted to string.
|
return String(value); // Ensure value is converted to string.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,12 +233,12 @@ class NotSupportedValidator extends ValueValidator {
|
|||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override validate(ignoredValue: string): IValidationResult {
|
public validate(ignoredValue: string): IValidationResult {
|
||||||
//throw new Errors.NotSupportedError(this.getMessage());
|
//throw new Errors.NotSupportedError(this.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override parseValue(ignoredValue: string): any {
|
public parseValue(ignoredValue: string): any {
|
||||||
//throw new Errors.NotSupportedError(this.getMessage());
|
//throw new Errors.NotSupportedError(this.getMessage());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user