Created selfServe landing page (#444)
* Portal changes for DedicatedGateway Changes to support creation and deletion of DedicatedGateway resource. Tested locally with various scenarios. * Portal changes for DedicatedGateway. CR feedback * Stylecop changes * created selfServe.html landing page * Removing TODO comments * exposed baselineValues * added getOnSaveNotification * disable UI when onSave is taking place * minro edits * made polling optional * added optional polling * added default * Added portal notifications * merged more changes * minor edits * added label for description * Added correlationids and polling of refresh * Added correlationids and polling of refresh * minor edit * added label tooltip * removed ClassInfo decorator * Added dynamic decription * added info and warninf types for description * more changes to promise retry * promise retry changes * added spinner on selfserve load * compile errors fixed * New changes * added operationstatus link * merged sqlxEdits * undid sqlx changes * added completed notification * passed retryInterval in notif options * more retry changes * more changes * added polling on landing on the page * edits for error display * added keys blade link * added link generation * added link to blade * Modified info and description * fixed format errors * added selfserve contract to output files * addressed PR comments Co-authored-by: Balaji Sridharan <fnbalaji@microsoft.com> Co-authored-by: fnbalaji <75445927+fnbalaji@users.noreply.github.com>
This commit is contained in:
parent
b85a20cbea
commit
1d98c83be5
|
@ -393,7 +393,16 @@ export interface DataExplorerInputsFrame {
|
||||||
isAuthWithresourceToken?: boolean;
|
isAuthWithresourceToken?: boolean;
|
||||||
defaultCollectionThroughput?: CollectionCreationDefaults;
|
defaultCollectionThroughput?: CollectionCreationDefaults;
|
||||||
flights?: readonly string[];
|
flights?: readonly string[];
|
||||||
selfServeType?: SelfServeType;
|
}
|
||||||
|
|
||||||
|
export interface SelfServeFrameInputs {
|
||||||
|
selfServeType: SelfServeType;
|
||||||
|
databaseAccount: any;
|
||||||
|
subscriptionId: string;
|
||||||
|
resourceGroup: string;
|
||||||
|
authorizationToken: string;
|
||||||
|
csmEndpoint: string;
|
||||||
|
flights?: readonly string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CollectionCreationDefaults {
|
export interface CollectionCreationDefaults {
|
||||||
|
|
|
@ -1060,14 +1060,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
},
|
},
|
||||||
"selectedDatabaseId": [Function],
|
"selectedDatabaseId": [Function],
|
||||||
"selectedNode": [Function],
|
"selectedNode": [Function],
|
||||||
"selfServeComponentAdapter": SelfServeComponentAdapter {
|
|
||||||
"container": [Circular],
|
|
||||||
"parameters": [Function],
|
|
||||||
},
|
|
||||||
"selfServeLoadingComponentAdapter": SelfServeLoadingComponentAdapter {
|
|
||||||
"parameters": [Function],
|
|
||||||
},
|
|
||||||
"selfServeType": [Function],
|
|
||||||
"serverId": [Function],
|
"serverId": [Function],
|
||||||
"setInProgressConsoleDataIdToBeDeleted": undefined,
|
"setInProgressConsoleDataIdToBeDeleted": undefined,
|
||||||
"setIsNotificationConsoleExpanded": undefined,
|
"setIsNotificationConsoleExpanded": undefined,
|
||||||
|
@ -2269,14 +2261,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
},
|
},
|
||||||
"selectedDatabaseId": [Function],
|
"selectedDatabaseId": [Function],
|
||||||
"selectedNode": [Function],
|
"selectedNode": [Function],
|
||||||
"selfServeComponentAdapter": SelfServeComponentAdapter {
|
|
||||||
"container": [Circular],
|
|
||||||
"parameters": [Function],
|
|
||||||
},
|
|
||||||
"selfServeLoadingComponentAdapter": SelfServeLoadingComponentAdapter {
|
|
||||||
"parameters": [Function],
|
|
||||||
},
|
|
||||||
"selfServeType": [Function],
|
|
||||||
"serverId": [Function],
|
"serverId": [Function],
|
||||||
"setInProgressConsoleDataIdToBeDeleted": undefined,
|
"setInProgressConsoleDataIdToBeDeleted": undefined,
|
||||||
"setIsNotificationConsoleExpanded": undefined,
|
"setIsNotificationConsoleExpanded": undefined,
|
||||||
|
@ -3491,14 +3475,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
},
|
},
|
||||||
"selectedDatabaseId": [Function],
|
"selectedDatabaseId": [Function],
|
||||||
"selectedNode": [Function],
|
"selectedNode": [Function],
|
||||||
"selfServeComponentAdapter": SelfServeComponentAdapter {
|
|
||||||
"container": [Circular],
|
|
||||||
"parameters": [Function],
|
|
||||||
},
|
|
||||||
"selfServeLoadingComponentAdapter": SelfServeLoadingComponentAdapter {
|
|
||||||
"parameters": [Function],
|
|
||||||
},
|
|
||||||
"selfServeType": [Function],
|
|
||||||
"serverId": [Function],
|
"serverId": [Function],
|
||||||
"setInProgressConsoleDataIdToBeDeleted": undefined,
|
"setInProgressConsoleDataIdToBeDeleted": undefined,
|
||||||
"setIsNotificationConsoleExpanded": undefined,
|
"setIsNotificationConsoleExpanded": undefined,
|
||||||
|
@ -4700,14 +4676,6 @@ exports[`SettingsComponent renders 1`] = `
|
||||||
},
|
},
|
||||||
"selectedDatabaseId": [Function],
|
"selectedDatabaseId": [Function],
|
||||||
"selectedNode": [Function],
|
"selectedNode": [Function],
|
||||||
"selfServeComponentAdapter": SelfServeComponentAdapter {
|
|
||||||
"container": [Circular],
|
|
||||||
"parameters": [Function],
|
|
||||||
},
|
|
||||||
"selfServeLoadingComponentAdapter": SelfServeLoadingComponentAdapter {
|
|
||||||
"parameters": [Function],
|
|
||||||
},
|
|
||||||
"selfServeType": [Function],
|
|
||||||
"serverId": [Function],
|
"serverId": [Function],
|
||||||
"setInProgressConsoleDataIdToBeDeleted": undefined,
|
"setInProgressConsoleDataIdToBeDeleted": undefined,
|
||||||
"setIsNotificationConsoleExpanded": undefined,
|
"setIsNotificationConsoleExpanded": undefined,
|
||||||
|
|
|
@ -127,8 +127,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||||
return (
|
return (
|
||||||
info && (
|
info && (
|
||||||
<Text>
|
<Text>
|
||||||
{this.props.getTranslation(info.messageTKey)}
|
{this.props.getTranslation(info.messageTKey)}{" "}
|
||||||
{` `}
|
|
||||||
{info.link && (
|
{info.link && (
|
||||||
<Link href={info.link.href} target="_blank">
|
<Link href={info.link.href} target="_blank">
|
||||||
{this.props.getTranslation(info.link.textTKey)}
|
{this.props.getTranslation(info.link.textTKey)}
|
||||||
|
@ -168,8 +167,7 @@ export class SmartUiComponent extends React.Component<SmartUiComponentProps, Sma
|
||||||
}
|
}
|
||||||
const descriptionElement = (
|
const descriptionElement = (
|
||||||
<Text id={`${dataFieldName}-text-display`} aria-labelledby={labelId}>
|
<Text id={`${dataFieldName}-text-display`} aria-labelledby={labelId}>
|
||||||
{this.props.getTranslation(description.textTKey)}
|
{this.props.getTranslation(description.textTKey)}{" "}
|
||||||
{` `}
|
|
||||||
{description.link && (
|
{description.link && (
|
||||||
<Link target="_blank" href={description.link.href}>
|
<Link target="_blank" href={description.link.href}>
|
||||||
{this.props.getTranslation(description.link.textTKey)}
|
{this.props.getTranslation(description.link.textTKey)}
|
||||||
|
|
|
@ -83,9 +83,6 @@ import { IChoiceGroupProps } from "office-ui-fabric-react";
|
||||||
import { getErrorMessage, handleError, getErrorStack } from "../Common/ErrorHandlingUtils";
|
import { getErrorMessage, handleError, getErrorStack } from "../Common/ErrorHandlingUtils";
|
||||||
import { SubscriptionType } from "../Contracts/SubscriptionType";
|
import { SubscriptionType } from "../Contracts/SubscriptionType";
|
||||||
import { appInsights } from "../Shared/appInsights";
|
import { appInsights } from "../Shared/appInsights";
|
||||||
import { SelfServeLoadingComponentAdapter } from "../SelfServe/SelfServeLoadingComponentAdapter";
|
|
||||||
import { SelfServeType } from "../SelfServe/SelfServeUtils";
|
|
||||||
import { SelfServeComponentAdapter } from "../SelfServe/SelfServeComponentAdapter";
|
|
||||||
import { GalleryTab } from "./Controls/NotebookGallery/GalleryViewerComponent";
|
import { GalleryTab } from "./Controls/NotebookGallery/GalleryViewerComponent";
|
||||||
import { DeleteCollectionConfirmationPanel } from "./Panes/DeleteCollectionConfirmationPanel";
|
import { DeleteCollectionConfirmationPanel } from "./Panes/DeleteCollectionConfirmationPanel";
|
||||||
|
|
||||||
|
@ -131,7 +128,6 @@ export default class Explorer {
|
||||||
public isEnableMongoCapabilityPresent: ko.Computed<boolean>;
|
public isEnableMongoCapabilityPresent: ko.Computed<boolean>;
|
||||||
public isServerlessEnabled: ko.Computed<boolean>;
|
public isServerlessEnabled: ko.Computed<boolean>;
|
||||||
public isAccountReady: ko.Observable<boolean>;
|
public isAccountReady: ko.Observable<boolean>;
|
||||||
public selfServeType: ko.Observable<SelfServeType>;
|
|
||||||
public canSaveQueries: ko.Computed<boolean>;
|
public canSaveQueries: ko.Computed<boolean>;
|
||||||
public features: ko.Observable<any>;
|
public features: ko.Observable<any>;
|
||||||
public serverId: ko.Observable<string>;
|
public serverId: ko.Observable<string>;
|
||||||
|
@ -159,7 +155,6 @@ export default class Explorer {
|
||||||
public selectedNode: ko.Observable<ViewModels.TreeNode>;
|
public selectedNode: ko.Observable<ViewModels.TreeNode>;
|
||||||
public isRefreshingExplorer: ko.Observable<boolean>;
|
public isRefreshingExplorer: ko.Observable<boolean>;
|
||||||
private resourceTree: ResourceTreeAdapter;
|
private resourceTree: ResourceTreeAdapter;
|
||||||
private selfServeComponentAdapter: SelfServeComponentAdapter;
|
|
||||||
|
|
||||||
// Resource Token
|
// Resource Token
|
||||||
public resourceTokenDatabaseId: ko.Observable<string>;
|
public resourceTokenDatabaseId: ko.Observable<string>;
|
||||||
|
@ -243,7 +238,6 @@ export default class Explorer {
|
||||||
|
|
||||||
// React adapters
|
// React adapters
|
||||||
private commandBarComponentAdapter: CommandBarComponentAdapter;
|
private commandBarComponentAdapter: CommandBarComponentAdapter;
|
||||||
private selfServeLoadingComponentAdapter: SelfServeLoadingComponentAdapter;
|
|
||||||
|
|
||||||
private static readonly MaxNbDatabasesToAutoExpand = 5;
|
private static readonly MaxNbDatabasesToAutoExpand = 5;
|
||||||
|
|
||||||
|
@ -287,7 +281,6 @@ export default class Explorer {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.isAccountReady = ko.observable<boolean>(false);
|
this.isAccountReady = ko.observable<boolean>(false);
|
||||||
this.selfServeType = ko.observable<SelfServeType>(undefined);
|
|
||||||
this._isInitializingNotebooks = false;
|
this._isInitializingNotebooks = false;
|
||||||
this.arcadiaToken = ko.observable<string>();
|
this.arcadiaToken = ko.observable<string>();
|
||||||
this.arcadiaToken.subscribe((token: string) => {
|
this.arcadiaToken.subscribe((token: string) => {
|
||||||
|
@ -662,7 +655,6 @@ export default class Explorer {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.uploadItemsPaneAdapter = new UploadItemsPaneAdapter(this);
|
this.uploadItemsPaneAdapter = new UploadItemsPaneAdapter(this);
|
||||||
this.selfServeComponentAdapter = new SelfServeComponentAdapter(this);
|
|
||||||
|
|
||||||
this.loadQueryPane = new LoadQueryPane({
|
this.loadQueryPane = new LoadQueryPane({
|
||||||
id: "loadquerypane",
|
id: "loadquerypane",
|
||||||
|
@ -837,7 +829,6 @@ export default class Explorer {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.commandBarComponentAdapter = new CommandBarComponentAdapter(this);
|
this.commandBarComponentAdapter = new CommandBarComponentAdapter(this);
|
||||||
this.selfServeLoadingComponentAdapter = new SelfServeLoadingComponentAdapter();
|
|
||||||
|
|
||||||
this._initSettings();
|
this._initSettings();
|
||||||
|
|
||||||
|
@ -1407,20 +1398,6 @@ export default class Explorer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setSelfServeType(inputs: ViewModels.DataExplorerInputsFrame): void {
|
|
||||||
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(SelfServeType.none);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public configure(inputs: ViewModels.DataExplorerInputsFrame): void {
|
public configure(inputs: ViewModels.DataExplorerInputsFrame): void {
|
||||||
if (inputs != null) {
|
if (inputs != null) {
|
||||||
// In development mode, save the iframe message from the portal in session storage.
|
// In development mode, save the iframe message from the portal in session storage.
|
||||||
|
@ -1446,7 +1423,6 @@ export default class Explorer {
|
||||||
this.isTryCosmosDBSubscription(inputs.isTryCosmosDBSubscription ?? false);
|
this.isTryCosmosDBSubscription(inputs.isTryCosmosDBSubscription ?? false);
|
||||||
this.isAuthWithResourceToken(inputs.isAuthWithresourceToken ?? false);
|
this.isAuthWithResourceToken(inputs.isAuthWithresourceToken ?? false);
|
||||||
this.setFeatureFlagsFromFlights(inputs.flights);
|
this.setFeatureFlagsFromFlights(inputs.flights);
|
||||||
this.setSelfServeType(inputs);
|
|
||||||
|
|
||||||
updateConfigContext({
|
updateConfigContext({
|
||||||
BACKEND_ENDPOINT: inputs.extensionEndpoint || configContext.BACKEND_ENDPOINT,
|
BACKEND_ENDPOINT: inputs.extensionEndpoint || configContext.BACKEND_ENDPOINT,
|
||||||
|
|
17
src/Main.tsx
17
src/Main.tsx
|
@ -105,17 +105,8 @@ const App: React.FunctionComponent = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flexContainer">
|
<div className="flexContainer">
|
||||||
<div
|
<div id="divExplorer" className="flexContainer hideOverflows" style={{ display: "none" }}>
|
||||||
id="divSelfServe"
|
{/* Main Command Bar - Start */}
|
||||||
className="flexContainer"
|
|
||||||
data-bind="visible: selfServeType() && selfServeType() !== 'none', react: selfServeComponentAdapter"
|
|
||||||
></div>
|
|
||||||
<div
|
|
||||||
id="divExplorer"
|
|
||||||
data-bind="if: selfServeType() === 'none'"
|
|
||||||
className="flexContainer hideOverflows"
|
|
||||||
style={{ display: "none" }}
|
|
||||||
>
|
|
||||||
<div data-bind="react: commandBarComponentAdapter" />
|
<div data-bind="react: commandBarComponentAdapter" />
|
||||||
{/* Collections Tree and Tabs - Begin */}
|
{/* Collections Tree and Tabs - Begin */}
|
||||||
<div className="resourceTreeAndTabs">
|
<div className="resourceTreeAndTabs">
|
||||||
|
@ -246,11 +237,8 @@ const App: React.FunctionComponent = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* Global loader - Start */}
|
{/* Global loader - Start */}
|
||||||
|
|
||||||
<div className="splashLoaderContainer" data-bind="visible: isRefreshingExplorer">
|
<div className="splashLoaderContainer" data-bind="visible: isRefreshingExplorer">
|
||||||
<div className="splashLoaderContentContainer">
|
<div className="splashLoaderContentContainer">
|
||||||
<div data-bind="visible: selfServeType() === undefined, react: selfServeLoadingComponentAdapter"></div>
|
|
||||||
<div data-bind="if: selfServeType() === 'none'" style={{ display: "none" }}>
|
|
||||||
<p className="connectExplorerContent">
|
<p className="connectExplorerContent">
|
||||||
<img src={hdeConnectImage} alt="Azure Cosmos DB" />
|
<img src={hdeConnectImage} alt="Azure Cosmos DB" />
|
||||||
</p>
|
</p>
|
||||||
|
@ -262,7 +250,6 @@ const App: React.FunctionComponent = () => {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{/* Global loader - End */}
|
{/* Global loader - End */}
|
||||||
<PanelContainerComponent
|
<PanelContainerComponent
|
||||||
isOpen={isPanelOpen}
|
isOpen={isPanelOpen}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
.selfServeComponentContainer {
|
||||||
|
text-transform: none;
|
||||||
|
line-height: 1.28581;
|
||||||
|
letter-spacing: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #182026;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
|
@ -0,0 +1,92 @@
|
||||||
|
import * as React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
|
import { sendMessage } from "../Common/MessageHandler";
|
||||||
|
import { isInvalidParentFrameOrigin } from "../Utils/MessageValidation";
|
||||||
|
import { SelfServeComponent } from "./SelfServeComponent";
|
||||||
|
import { SelfServeDescriptor } from "./SelfServeTypes";
|
||||||
|
import { SelfServeType } from "./SelfServeUtils";
|
||||||
|
import { SelfServeFrameInputs } from "../Contracts/ViewModels";
|
||||||
|
import { initializeIcons } from "office-ui-fabric-react/lib/Icons";
|
||||||
|
import { configContext, updateConfigContext } from "../ConfigContext";
|
||||||
|
import { normalizeArmEndpoint } from "../Common/EnvironmentUtility";
|
||||||
|
import { updateUserContext } from "../UserContext";
|
||||||
|
import "./SelfServe.less";
|
||||||
|
import { Spinner, SpinnerSize } from "office-ui-fabric-react";
|
||||||
|
initializeIcons();
|
||||||
|
|
||||||
|
const getDescriptor = async (selfServeType: SelfServeType): Promise<SelfServeDescriptor> => {
|
||||||
|
switch (selfServeType) {
|
||||||
|
case SelfServeType.example: {
|
||||||
|
const SelfServeExample = await import(/* webpackChunkName: "SelfServeExample" */ "./Example/SelfServeExample");
|
||||||
|
return new SelfServeExample.default().toSelfServeDescriptor();
|
||||||
|
}
|
||||||
|
case SelfServeType.sqlx: {
|
||||||
|
const SqlX = await import(/* webpackChunkName: "SqlX" */ "./SqlX/SqlX");
|
||||||
|
return new SqlX.default().toSelfServeDescriptor();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderComponent = (selfServeDescriptor: SelfServeDescriptor): JSX.Element => {
|
||||||
|
if (!selfServeDescriptor) {
|
||||||
|
return <h1>Invalid self serve type!</h1>;
|
||||||
|
}
|
||||||
|
return <SelfServeComponent descriptor={selfServeDescriptor} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderSpinner = (): JSX.Element => {
|
||||||
|
return <Spinner size={SpinnerSize.large}></Spinner>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMessage = async (event: MessageEvent): Promise<void> => {
|
||||||
|
if (isInvalidParentFrameOrigin(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.data["signature"] !== "pcIframe") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof event.data !== "object") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const inputs = event.data.data.inputs as SelfServeFrameInputs;
|
||||||
|
if (!inputs) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||||
|
const selfServeTypeText = inputs.selfServeType || urlSearchParams.get("selfServeType");
|
||||||
|
const selfServeType = SelfServeType[selfServeTypeText?.toLowerCase() as keyof typeof SelfServeType];
|
||||||
|
if (
|
||||||
|
!inputs.subscriptionId ||
|
||||||
|
!inputs.resourceGroup ||
|
||||||
|
!inputs.databaseAccount ||
|
||||||
|
!inputs.authorizationToken ||
|
||||||
|
!inputs.csmEndpoint ||
|
||||||
|
!selfServeType
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConfigContext({
|
||||||
|
ARM_ENDPOINT: normalizeArmEndpoint(inputs.csmEndpoint || configContext.ARM_ENDPOINT),
|
||||||
|
});
|
||||||
|
|
||||||
|
updateUserContext({
|
||||||
|
authorizationToken: inputs.authorizationToken,
|
||||||
|
databaseAccount: inputs.databaseAccount,
|
||||||
|
resourceGroup: inputs.resourceGroup,
|
||||||
|
subscriptionId: inputs.subscriptionId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const descriptor = await getDescriptor(selfServeType);
|
||||||
|
ReactDOM.render(renderComponent(descriptor), document.getElementById("selfServeContent"));
|
||||||
|
};
|
||||||
|
|
||||||
|
ReactDOM.render(renderSpinner(), document.getElementById("selfServeContent"));
|
||||||
|
window.addEventListener("message", handleMessage, false);
|
||||||
|
sendMessage("ready");
|
|
@ -1,56 +0,0 @@
|
||||||
/**
|
|
||||||
* This adapter is responsible to render the React component
|
|
||||||
* If the component signals a change through the callback passed in the properties, it must render the React component when appropriate
|
|
||||||
* and update any knockout observables passed from the parent.
|
|
||||||
*/
|
|
||||||
import * as ko from "knockout";
|
|
||||||
import * as React from "react";
|
|
||||||
import { ReactAdapter } from "../Bindings/ReactBindingHandler";
|
|
||||||
import Explorer from "../Explorer/Explorer";
|
|
||||||
import { SelfServeComponent } from "./SelfServeComponent";
|
|
||||||
import { SelfServeDescriptor } from "./SelfServeTypes";
|
|
||||||
import { SelfServeType } from "./SelfServeUtils";
|
|
||||||
|
|
||||||
export class SelfServeComponentAdapter implements ReactAdapter {
|
|
||||||
public parameters: ko.Observable<SelfServeDescriptor>;
|
|
||||||
public container: Explorer;
|
|
||||||
|
|
||||||
constructor(container: Explorer) {
|
|
||||||
this.container = container;
|
|
||||||
this.parameters = ko.observable(undefined);
|
|
||||||
this.container.selfServeType.subscribe(() => {
|
|
||||||
this.triggerRender();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static getDescriptor = async (selfServeType: SelfServeType): Promise<SelfServeDescriptor> => {
|
|
||||||
switch (selfServeType) {
|
|
||||||
case SelfServeType.example: {
|
|
||||||
const SelfServeExample = await import(/* webpackChunkName: "SelfServeExample" */ "./Example/SelfServeExample");
|
|
||||||
return new SelfServeExample.default().toSelfServeDescriptor();
|
|
||||||
}
|
|
||||||
case SelfServeType.sqlx: {
|
|
||||||
const SqlX = await import(/* webpackChunkName: "SqlX" */ "./SqlX/SqlX");
|
|
||||||
return new SqlX.default().toSelfServeDescriptor();
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public renderComponent(): JSX.Element {
|
|
||||||
if (this.container.selfServeType() === SelfServeType.invalid) {
|
|
||||||
return <h1>Invalid self serve type!</h1>;
|
|
||||||
}
|
|
||||||
const smartUiDescriptor = this.parameters();
|
|
||||||
return smartUiDescriptor ? <SelfServeComponent descriptor={smartUiDescriptor} /> : <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
private triggerRender() {
|
|
||||||
window.requestAnimationFrame(async () => {
|
|
||||||
const selfServeType = this.container.selfServeType();
|
|
||||||
const smartUiDescriptor = await SelfServeComponentAdapter.getDescriptor(selfServeType);
|
|
||||||
this.parameters(smartUiDescriptor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
/**
|
|
||||||
* This adapter is responsible to render the React component
|
|
||||||
* If the component signals a change through the callback passed in the properties, it must render the React component when appropriate
|
|
||||||
* and update any knockout observables passed from the parent.
|
|
||||||
*/
|
|
||||||
import * as ko from "knockout";
|
|
||||||
import { Spinner, SpinnerSize } from "office-ui-fabric-react";
|
|
||||||
import * as React from "react";
|
|
||||||
import { ReactAdapter } from "../Bindings/ReactBindingHandler";
|
|
||||||
|
|
||||||
export class SelfServeLoadingComponentAdapter implements ReactAdapter {
|
|
||||||
public parameters: ko.Observable<number>;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.parameters = ko.observable(Date.now());
|
|
||||||
}
|
|
||||||
|
|
||||||
public renderComponent(): JSX.Element {
|
|
||||||
return <Spinner size={SpinnerSize.large} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
private triggerRender() {
|
|
||||||
window.requestAnimationFrame(() => this.renderComponent());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="selfServeViewport" content="height=device-height, width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Self Serve</title>
|
||||||
|
<link rel="shortcut icon" href="images/CosmosDB_rgb_ui_lighttheme.ico" type="image/x-icon" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="selfServeComponentContainer" id="selfServeContent"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -23,7 +23,6 @@ import {
|
||||||
getDatabaseAccountKindFromExperience,
|
getDatabaseAccountKindFromExperience,
|
||||||
getDatabaseAccountPropertiesFromMetadata,
|
getDatabaseAccountPropertiesFromMetadata,
|
||||||
} from "../Platform/Hosted/HostedUtils";
|
} from "../Platform/Hosted/HostedUtils";
|
||||||
import { SelfServeType } from "../SelfServe/SelfServeUtils";
|
|
||||||
import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility";
|
import { DefaultExperienceUtility } from "../Shared/DefaultExperienceUtility";
|
||||||
import { updateUserContext } from "../UserContext";
|
import { updateUserContext } from "../UserContext";
|
||||||
import { listKeys } from "../Utils/arm/generatedClients/2020-04-01/databaseAccounts";
|
import { listKeys } from "../Utils/arm/generatedClients/2020-04-01/databaseAccounts";
|
||||||
|
@ -57,7 +56,6 @@ export function useKnockoutExplorer(platform: Platform, explorerParams: Explorer
|
||||||
|
|
||||||
async function configureHosted() {
|
async function configureHosted() {
|
||||||
const win = (window as unknown) as HostedExplorerChildFrame;
|
const win = (window as unknown) as HostedExplorerChildFrame;
|
||||||
explorer.selfServeType(SelfServeType.none);
|
|
||||||
if (win.hostedConfig.authType === AuthType.EncryptedToken) {
|
if (win.hostedConfig.authType === AuthType.EncryptedToken) {
|
||||||
configureHostedWithEncryptedToken(win.hostedConfig);
|
configureHostedWithEncryptedToken(win.hostedConfig);
|
||||||
} else if (win.hostedConfig.authType === AuthType.ResourceToken) {
|
} else if (win.hostedConfig.authType === AuthType.ResourceToken) {
|
||||||
|
@ -161,7 +159,6 @@ function configureEmulator() {
|
||||||
updateUserContext({
|
updateUserContext({
|
||||||
authType: AuthType.MasterKey,
|
authType: AuthType.MasterKey,
|
||||||
});
|
});
|
||||||
explorer.selfServeType(SelfServeType.none);
|
|
||||||
explorer.databaseAccount(emulatorAccount);
|
explorer.databaseAccount(emulatorAccount);
|
||||||
explorer.isAccountReady(true);
|
explorer.isAccountReady(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,8 +127,16 @@ const initTestExplorer = async (): Promise<void> => {
|
||||||
iframe.name = "explorer";
|
iframe.name = "explorer";
|
||||||
iframe.classList.add("iframe");
|
iframe.classList.add("iframe");
|
||||||
iframe.title = "explorer";
|
iframe.title = "explorer";
|
||||||
iframe.src = "explorer.html?platform=Portal&disablePortalInitCache";
|
iframe.src = getIframeSrc(selfServeType);
|
||||||
document.body.appendChild(iframe);
|
document.body.appendChild(iframe);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getIframeSrc = (selfServeType: string): string => {
|
||||||
|
let iframeSrc = "explorer.html?platform=Portal&disablePortalInitCache";
|
||||||
|
if (selfServeType) {
|
||||||
|
iframeSrc = `selfServe.html?selfServeType=${selfServeType}`;
|
||||||
|
}
|
||||||
|
return iframeSrc;
|
||||||
|
};
|
||||||
|
|
||||||
initTestExplorer();
|
initTestExplorer();
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
"./src/Contracts/ActionContracts.ts",
|
"./src/Contracts/ActionContracts.ts",
|
||||||
"./src/Contracts/Diagnostics.ts",
|
"./src/Contracts/Diagnostics.ts",
|
||||||
"./src/Contracts/ExplorerContracts.ts",
|
"./src/Contracts/ExplorerContracts.ts",
|
||||||
|
"./src/Contracts/SelfServeContracts.ts",
|
||||||
"./src/Contracts/Versions.ts"
|
"./src/Contracts/Versions.ts"
|
||||||
],
|
],
|
||||||
}
|
}
|
|
@ -166,6 +166,11 @@ module.exports = function (env = {}, argv = {}) {
|
||||||
template: "src/connectToGitHub.html",
|
template: "src/connectToGitHub.html",
|
||||||
chunks: ["connectToGitHub"],
|
chunks: ["connectToGitHub"],
|
||||||
}),
|
}),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: "selfServe.html",
|
||||||
|
template: "src/SelfServe/selfServe.html",
|
||||||
|
chunks: ["selfServe"],
|
||||||
|
}),
|
||||||
new MonacoWebpackPlugin(),
|
new MonacoWebpackPlugin(),
|
||||||
new CopyWebpackPlugin({
|
new CopyWebpackPlugin({
|
||||||
patterns: [{ from: "DataExplorer.nuspec" }, { from: "web.config" }, { from: "quickstart/*.zip" }],
|
patterns: [{ from: "DataExplorer.nuspec" }, { from: "web.config" }, { from: "quickstart/*.zip" }],
|
||||||
|
@ -189,6 +194,7 @@ module.exports = function (env = {}, argv = {}) {
|
||||||
terminal: "./src/Terminal/index.ts",
|
terminal: "./src/Terminal/index.ts",
|
||||||
notebookViewer: "./src/NotebookViewer/NotebookViewer.tsx",
|
notebookViewer: "./src/NotebookViewer/NotebookViewer.tsx",
|
||||||
galleryViewer: "./src/GalleryViewer/GalleryViewer.tsx",
|
galleryViewer: "./src/GalleryViewer/GalleryViewer.tsx",
|
||||||
|
selfServe: "./src/SelfServe/SelfServe.tsx",
|
||||||
connectToGitHub: "./src/GitHub/GitHubConnector.ts",
|
connectToGitHub: "./src/GitHub/GitHubConnector.ts",
|
||||||
},
|
},
|
||||||
node: {
|
node: {
|
||||||
|
|
Loading…
Reference in New Issue