mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-23 02:41:39 +00:00
Removed reactbinding changes
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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()} />
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
/*
|
||||
|
||||
@@ -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)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user