Removed reactbinding changes

This commit is contained in:
Srinath Narayanan
2021-01-15 07:09:14 -08:00
parent 41f37055ef
commit 3fb4af53c8
11 changed files with 68 additions and 73 deletions

View File

@@ -15,7 +15,7 @@ import * as ReactDOM from "react-dom";
export interface ReactAdapter {
parameters: any;
renderComponent: (() => Promise<JSX.Element>) | (() => JSX.Element);
renderComponent: () => JSX.Element;
setElement?: (elt: Element) => void;
}
@@ -36,12 +36,12 @@ export class Registerer {
}
// If any of the ko observable change inside parameters, trigger a new render.
ko.computed(() => ko.toJSON(adapter.parameters)).subscribe(async () =>
ReactDOM.render(await adapter.renderComponent(), element)
ko.computed(() => ko.toJSON(adapter.parameters)).subscribe(() =>
ReactDOM.render(adapter.renderComponent(), element)
);
// Initial rendering at mount point
Promise.resolve(adapter.renderComponent()).then(component => ReactDOM.render(component, element));
ReactDOM.render(adapter.renderComponent(), element);
}
} as ko.BindingHandler;
}

View File

@@ -126,7 +126,7 @@ export class Features {
public static readonly enableSchema = "enableschema";
public static readonly enableSDKoperations = "enablesdkoperations";
public static readonly showMinRUSurvey = "showminrusurvey";
public static readonly selfServeTypeForTest = "selfservetypefortest";
public static readonly selfServeType = "selfservetype";
}
// flight names returned from the portal are always lowercase

View File

@@ -15,7 +15,7 @@ import DocumentId from "../Explorer/Tree/DocumentId";
import StoredProcedure from "../Explorer/Tree/StoredProcedure";
import Trigger from "../Explorer/Tree/Trigger";
import UserDefinedFunction from "../Explorer/Tree/UserDefinedFunction";
import { SelfServeTypes } from "../SelfServe/SelfServeUtils";
import { SelfServeType } from "../SelfServe/SelfServeUtils";
import { UploadDetails } from "../workers/upload/definitions";
import * as DataModels from "./DataModels";
import { SubscriptionType } from "./SubscriptionType";
@@ -396,7 +396,7 @@ export interface DataExplorerInputsFrame {
isAuthWithresourceToken?: boolean;
defaultCollectionThroughput?: CollectionCreationDefaults;
flights?: readonly string[];
selfServeType?: SelfServeTypes;
selfServeType?: SelfServeType;
}
export interface CollectionCreationDefaults {

View File

@@ -48,7 +48,7 @@ export const FeaturePanelComponent: React.FunctionComponent = () => {
{ key: "feature.hosteddataexplorerenabled", label: "Hosted Data Explorer (deprecated?)", value: "true" },
{ key: "feature.enablettl", label: "Enable TTL", value: "true" },
{ key: "feature.enablegallerypublish", label: "Enable Notebook Gallery Publishing", value: "true" },
{ key: "feature.selfServeTypeForTest", label: "Self serve type passed on for testing", value: "sample" },
{ key: "feature.selfServeType", label: "Self serve feature", value: "sample" },
{
key: "feature.enableLinkInjection",
label: "Enable Injecting Notebook Viewer Link into the first cell",

View File

@@ -5,7 +5,6 @@ import { SpinButton } from "office-ui-fabric-react/lib/SpinButton";
import { Dropdown, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
import { TextField } from "office-ui-fabric-react/lib/TextField";
import { Text } from "office-ui-fabric-react/lib/Text";
import { InputType } from "../../Tables/Constants";
import { RadioSwitchComponent } from "../RadioSwitchComponent/RadioSwitchComponent";
import { Stack, IStackTokens } from "office-ui-fabric-react/lib/Stack";
import { Link, MessageBar, MessageBarType, PrimaryButton, Spinner, SpinnerSize } from "office-ui-fabric-react";
@@ -35,7 +34,7 @@ type infoPromise = () => Promise<Info>;
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
export type DropdownItem = { label: string; key: string };
export type InputType = number | string | boolean | DropdownItem | JSX.Element;
export type InputType = number | string | boolean | DropdownItem;
export interface BaseInput {
label: (() => Promise<string>) | string;
@@ -117,7 +116,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
};
componentDidMount(): void {
this.setDefaultValues();
this.initializeSmartUiComponent();
}
constructor(props: SmartUiComponentProps) {
@@ -130,23 +129,25 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
};
}
private setDefaultValues = async (): Promise<void> => {
private initializeSmartUiComponent = async (): Promise<void> => {
this.setState({ isRefreshing: true });
await this.setDefaults(this.props.descriptor.root);
await this.initializeNode(this.props.descriptor.root);
await this.setDefaults();
this.setState({ isRefreshing: false });
await this.initialize();
};
private initialize = async (): Promise<void> => {
private setDefaults = async (): Promise<void> => {
this.setState({ isRefreshing: true });
let { currentValues, baselineValues } = this.state;
const initialValues = await this.props.descriptor.initialize();
for (const key of initialValues.keys()) {
if (this.props.descriptor.inputNames.indexOf(key) === -1) {
console.log(this.props.descriptor.inputNames);
this.setState({ isRefreshing: false });
throw new Error(`${key} is not an input property of this class.`);
}
currentValues = currentValues.set(key, initialValues.get(key));
baselineValues = baselineValues.set(key, initialValues.get(key));
}
@@ -162,7 +163,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
this.setState({ currentValues: currentValues });
};
private setDefaults = async (currentNode: Node): Promise<void> => {
private initializeNode = async (currentNode: Node): Promise<void> => {
if (currentNode.info && currentNode.info instanceof Function) {
currentNode.info = await (currentNode.info as infoPromise)();
}
@@ -170,7 +171,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
if (currentNode.input) {
currentNode.input = await this.getModifiedInput(currentNode.input);
}
const promises = currentNode.children?.map(async (child: Node) => await this.setDefaults(child));
const promises = currentNode.children?.map(async (child: Node) => await this.initializeNode(child));
if (promises) {
await Promise.all(promises);
}
@@ -222,24 +223,6 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
}
};
private getDefaultValue = (input: AnyInput): InputType => {
switch (input.type) {
case "string": {
const stringInput = input as StringInput;
return stringInput.defaultValue ? (stringInput.defaultValue as string) : "";
}
case "number": {
return (input as NumberInput).defaultValue as number;
}
case "boolean": {
return (input as BooleanInput).defaultValue as boolean;
}
default: {
return (input as DropdownInput).defaultKey as string;
}
}
};
private renderInfo(info: Info): JSX.Element {
return (
<MessageBar>
@@ -265,7 +248,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
}
};
private renderStringInput(input: StringInput): JSX.Element {
private renderTextInput(input: StringInput): JSX.Element {
const value = this.state.currentValues.get(input.dataFieldName) as string;
return (
<div className="stringInputContainer">
@@ -423,7 +406,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
);
}
private renderEnumInput(input: DropdownInput): JSX.Element {
private renderDropdownInput(input: DropdownInput): JSX.Element {
const { label, defaultKey: defaultKey, dataFieldName, choices, placeholder } = input;
return (
<Dropdown
@@ -460,13 +443,15 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
}
switch (input.type) {
case "string":
return this.renderStringInput(input as StringInput);
return this.renderTextInput(input as StringInput);
case "number":
return this.renderNumberInput(input as NumberInput);
case "boolean":
return this.renderBooleanInput(input as BooleanInput);
case "object":
return this.renderDropdownInput(input as DropdownInput);
default:
return this.renderEnumInput(input as DropdownInput);
throw new Error(`Unknown input type: ${input.type}`);
}
}
@@ -496,7 +481,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
text="submit"
onClick={async () => {
await this.props.descriptor.onSubmit(this.state.currentValues);
this.initialize();
this.setDefaults();
}}
/>
<PrimaryButton styles={{ root: { width: 100 } }} text="discard" onClick={() => this.discard()} />

View File

@@ -89,7 +89,7 @@ import { IChoiceGroupProps } from "office-ui-fabric-react";
import { getErrorMessage, handleError, getErrorStack } from "../Common/ErrorHandlingUtils";
import { SubscriptionType } from "../Contracts/SubscriptionType";
import { SelfServeLoadingComponentAdapter } from "../SelfServe/SelfServeLoadingComponentAdapter";
import { SelfServeTypes } from "../SelfServe/SelfServeUtils";
import { SelfServeType } from "../SelfServe/SelfServeUtils";
import { SelfServeComponentAdapter } from "../SelfServe/SelfServeComponentAdapter";
BindingHandlersRegisterer.registerBindingHandlers();
@@ -134,7 +134,7 @@ export default class Explorer {
public isEnableMongoCapabilityPresent: ko.Computed<boolean>;
public isServerlessEnabled: ko.Computed<boolean>;
public isAccountReady: ko.Observable<boolean>;
public selfServeType: ko.Observable<SelfServeTypes>;
public selfServeType: ko.Observable<SelfServeType>;
public canSaveQueries: ko.Computed<boolean>;
public features: ko.Observable<any>;
public serverId: ko.Observable<string>;
@@ -299,7 +299,7 @@ export default class Explorer {
}
});
this.isAccountReady = ko.observable<boolean>(false);
this.selfServeType = ko.observable<SelfServeTypes>(undefined);
this.selfServeType = ko.observable<SelfServeType>(undefined);
this._isInitializingNotebooks = false;
this._isInitializingSparkConnectionInfo = false;
this.arcadiaToken = ko.observable<string>();
@@ -1851,14 +1851,16 @@ export default class Explorer {
}
public setSelfServeType(inputs: ViewModels.DataExplorerInputsFrame): void {
const selfServeTypeForTest = inputs.features[Constants.Features.selfServeTypeForTest];
if (selfServeTypeForTest) {
const selfServeType = SelfServeTypes[selfServeTypeForTest?.toLowerCase() as keyof typeof SelfServeTypes];
this.selfServeType(selfServeType ? selfServeType : SelfServeTypes.invalid);
const selfServeFeature = inputs.features[Constants.Features.selfServeType];
if (selfServeFeature) {
// self serve type received from query string
const selfServeType = SelfServeType[selfServeFeature?.toLowerCase() as keyof typeof SelfServeType];
this.selfServeType(selfServeType ? selfServeType : SelfServeType.invalid);
} else if (inputs.selfServeType) {
// self serve type received from portal
this.selfServeType(inputs.selfServeType);
} else {
this.selfServeType(SelfServeTypes.none);
this.selfServeType(SelfServeType.none);
}
}

View File

@@ -79,6 +79,7 @@ import refreshImg from "../images/refresh-cosmos.svg";
import arrowLeftImg from "../images/imgarrowlefticon.svg";
import { KOCommentEnd, KOCommentIfStart } from "./koComment";
import { Spinner, SpinnerSize } from "office-ui-fabric-react";
import { SelfServeType } from "./SelfServe/SelfServeUtils";
// TODO: Encapsulate and reuse all global variables as environment variables
window.authType = AuthType.AAD;
@@ -382,7 +383,6 @@ const App: React.FunctionComponent = () => {
</div>
{/* Explorer Connection - Encryption Token / AAD - End */}
{/* Global loader - Start */}
{window.dataExplorer && <Spinner size={SpinnerSize.large} />}
<div className="splashLoaderContainer" data-bind="visible: isRefreshingExplorer">
<div className="splashLoaderContentContainer">
@@ -391,8 +391,10 @@ const App: React.FunctionComponent = () => {
<p className="connectExplorerContent">
<img src={hdeConnectImage} alt="Azure Cosmos DB" />
</p>
<p className="splashLoaderTitle">Welcome to Azure Cosmos DB</p>
<p className="splashLoaderText" role="alert">
<p className="splashLoaderTitle" id="explorerLoadingStatusTitle">
Welcome to Azure Cosmos DB
</p>
<p className="splashLoaderText" id="explorerLoadingStatusText" role="alert">
Connecting...
</p>
</div>

View File

@@ -49,13 +49,13 @@ const initializeMaxThroughput = async (): Promise<number> => {
- Needs to define an onSubmit() function, a callback for when the submit button is clicked.
- Needs to define an initialize() function, to set default values for the inputs.
You can test this self serve UI by using the featureflag '?feature.selfServeTypeForTest=example'
You can test this self serve UI by using the featureflag '?feature.selfServeType=example'
and plumb in similar feature flags for your own self serve class.
*/
/*
@IsDisplayable()
- role: Generated the JSON required to convert this class into the required UI. This is done during compile time.
- role: Indicates to the compiler that UI should be generated from this class.
*/
@IsDisplayable()
/*

View File

@@ -8,23 +8,23 @@ import * as React from "react";
import { ReactAdapter } from "../Bindings/ReactBindingHandler";
import Explorer from "../Explorer/Explorer";
import { Descriptor, SmartUiComponent } from "../Explorer/Controls/SmartUi/SmartUiComponent";
import { SelfServeTypes } from "./SelfServeUtils";
import { SelfServeType } from "./SelfServeUtils";
export class SelfServeComponentAdapter implements ReactAdapter {
public parameters: ko.Observable<number>;
public parameters: ko.Observable<Descriptor>;
public container: Explorer;
constructor(container: Explorer) {
this.container = container;
this.parameters = ko.observable(Date.now());
this.parameters = ko.observable(undefined)
this.container.selfServeType.subscribe(() => {
this.triggerRender();
});
}
public static getDescriptor = async (selfServeType: SelfServeTypes): Promise<Descriptor> => {
public static getDescriptor = async (selfServeType: SelfServeType): Promise<Descriptor> => {
switch (selfServeType) {
case SelfServeTypes.example: {
case SelfServeType.example: {
const SelfServeExample = await import(/* webpackChunkName: "SelfServeExample" */ "./Example/SelfServeExample");
return new SelfServeExample.default().toSmartUiDescriptor();
}
@@ -33,20 +33,23 @@ export class SelfServeComponentAdapter implements ReactAdapter {
}
};
public async renderComponent(): Promise<JSX.Element> {
const selfServeType = this.container.selfServeType();
const smartUiDescriptor = await SelfServeComponentAdapter.getDescriptor(selfServeType);
const element = smartUiDescriptor ? (
public renderComponent(): JSX.Element {
if (this.container.selfServeType() === SelfServeType.invalid) {
return <h1>Invalid self serve type!</h1>
}
const smartUiDescriptor = this.parameters()
return smartUiDescriptor ? (
<SmartUiComponent descriptor={smartUiDescriptor} />
) : (
<h1>Invalid self serve type!</h1>
<></>
);
return element;
}
private triggerRender() {
window.requestAnimationFrame(() => this.parameters(Date.now()));
window.requestAnimationFrame(async () => {
const selfServeType = this.container.selfServeType();
const smartUiDescriptor = await SelfServeComponentAdapter.getDescriptor(selfServeType);
this.parameters(smartUiDescriptor)
});
}
}

View File

@@ -13,9 +13,12 @@ import {
InputType
} from "../Explorer/Controls/SmartUi/SmartUiComponent";
export enum SelfServeTypes {
export enum SelfServeType {
// No self serve type passed, launch explorer
none = "none",
// Unsupported self serve type passed as feature flag
invalid = "invalid",
// Add your self serve types here
example = "example"
}

View File

@@ -1,16 +1,16 @@
import { Frame } from "puppeteer";
import { TestExplorerParams } from "../testExplorer/TestExplorerParams";
import { getTestExplorerFrame } from "../testExplorer/TestExplorerUtils";
import { SelfServeTypes } from "../../src/SelfServe/SelfServeUtils";
import { SelfServeType } from "../../src/SelfServe/SelfServeUtils";
jest.setTimeout(300000);
let frame: Frame;
describe("Notebook UI tests", () => {
it("Upload, Open and Delete Notebook", async () => {
describe("Self Serve", () => {
it("Launch Self Serve Example", async () => {
try {
frame = await getTestExplorerFrame(
new Map<string, string>([[TestExplorerParams.selfServeType, SelfServeTypes.example]])
new Map<string, string>([[TestExplorerParams.selfServeType, SelfServeType.example]])
);
await frame.waitForSelector(".ms-Dropdown");
const dropdownLabel = await frame.$eval(".ms-Dropdown-label", element => element.textContent);