mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-20 17:30:46 +00:00
Migrated Hosted Explorer to React (#360)
Co-authored-by: Victor Meng <vimeng@microsoft.com> Co-authored-by: Steve Faulkner <stfaul@microsoft.com>
This commit is contained in:
@@ -1,108 +0,0 @@
|
||||
import React from "react";
|
||||
import { shallow, mount } from "enzyme";
|
||||
import { MeControlComponent, MeControlComponentProps } from "./MeControlComponent";
|
||||
|
||||
const createNotSignedInProps = (): MeControlComponentProps => {
|
||||
return {
|
||||
isUserSignedIn: false,
|
||||
user: null,
|
||||
onSignInClick: jest.fn(),
|
||||
onSignOutClick: jest.fn(),
|
||||
onSwitchDirectoryClick: jest.fn()
|
||||
};
|
||||
};
|
||||
|
||||
const createSignedInProps = (): MeControlComponentProps => {
|
||||
return {
|
||||
isUserSignedIn: true,
|
||||
user: {
|
||||
name: "Test User",
|
||||
email: "testuser@contoso.com",
|
||||
tenantName: "Contoso",
|
||||
imageUrl: "../../../../images/dotnet.png"
|
||||
},
|
||||
onSignInClick: jest.fn(),
|
||||
onSignOutClick: jest.fn(),
|
||||
onSwitchDirectoryClick: jest.fn()
|
||||
};
|
||||
};
|
||||
|
||||
describe("test render", () => {
|
||||
it("renders not signed in", () => {
|
||||
const props = createNotSignedInProps();
|
||||
|
||||
const wrapper = shallow(<MeControlComponent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders signed in with full info", () => {
|
||||
const props = createSignedInProps();
|
||||
|
||||
const wrapper = shallow(<MeControlComponent {...props} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("change not signed in to signed in", () => {
|
||||
const notSignInProps = createNotSignedInProps();
|
||||
|
||||
const wrapper = mount(<MeControlComponent {...notSignInProps} />);
|
||||
expect(wrapper.exists(".mecontrolSigninButton")).toBe(true);
|
||||
expect(wrapper.exists(".mecontrolHeaderButton")).toBe(false);
|
||||
|
||||
const signInProps = createSignedInProps();
|
||||
|
||||
wrapper.setProps(signInProps);
|
||||
expect(wrapper.exists(".mecontrolSigninButton")).toBe(false);
|
||||
expect(wrapper.exists(".mecontrolHeaderButton")).toBe(true);
|
||||
|
||||
wrapper.unmount;
|
||||
});
|
||||
|
||||
it("render contextual menu", () => {
|
||||
const signInProps = createSignedInProps();
|
||||
const wrapper = mount(<MeControlComponent {...signInProps} />);
|
||||
|
||||
wrapper.find("button.mecontrolHeaderButton").simulate("click");
|
||||
expect(wrapper.exists(".mecontrolContextualMenu")).toBe(true);
|
||||
|
||||
wrapper.find("button.mecontrolHeaderButton").simulate("click");
|
||||
expect(wrapper.exists(".mecontrolContextualMenu")).toBe(false);
|
||||
|
||||
wrapper.unmount;
|
||||
});
|
||||
});
|
||||
|
||||
describe("test function got called", () => {
|
||||
it("sign in click", () => {
|
||||
const notSignInProps = createNotSignedInProps();
|
||||
const wrapper = mount(<MeControlComponent {...notSignInProps} />);
|
||||
|
||||
wrapper.find("button.mecontrolSigninButton").simulate("click");
|
||||
expect(notSignInProps.onSignInClick).toBeCalled();
|
||||
expect(notSignInProps.onSignInClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("sign out click", () => {
|
||||
const signInProps = createSignedInProps();
|
||||
const wrapper = mount(<MeControlComponent {...signInProps} />);
|
||||
|
||||
wrapper.find("button.mecontrolHeaderButton").simulate("click");
|
||||
expect(wrapper.exists(".mecontrolContextualMenu")).toBe(true);
|
||||
|
||||
wrapper.find("div.signOutLink").simulate("click");
|
||||
expect(signInProps.onSignOutClick).toBeCalled();
|
||||
expect(signInProps.onSignOutClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("switch directory", () => {
|
||||
const signInProps = createSignedInProps();
|
||||
const wrapper = mount(<MeControlComponent {...signInProps} />);
|
||||
|
||||
wrapper.find("button.mecontrolHeaderButton").simulate("click");
|
||||
expect(wrapper.exists(".mecontrolContextualMenu")).toBe(true);
|
||||
|
||||
wrapper.find("div.switchDirectoryLink").simulate("click");
|
||||
expect(signInProps.onSwitchDirectoryClick).toBeCalled();
|
||||
expect(signInProps.onSwitchDirectoryClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,167 +0,0 @@
|
||||
import * as React from "react";
|
||||
import { DefaultButton, BaseButton, IButtonProps } from "office-ui-fabric-react/lib/Button";
|
||||
import { DirectionalHint, IContextualMenuProps } from "office-ui-fabric-react/lib/ContextualMenu";
|
||||
import { FocusZone } from "office-ui-fabric-react/lib/FocusZone";
|
||||
import { IPersonaSharedProps, Persona, PersonaInitialsColor, PersonaSize } from "office-ui-fabric-react/lib/Persona";
|
||||
|
||||
export interface MeControlComponentProps {
|
||||
/**
|
||||
* Wheather user is signed in or not
|
||||
*/
|
||||
isUserSignedIn: boolean;
|
||||
/**
|
||||
* User info
|
||||
*/
|
||||
user: MeControlUser;
|
||||
/**
|
||||
* Click handler for sign in click
|
||||
*/
|
||||
onSignInClick: (e: React.MouseEvent<BaseButton>) => void;
|
||||
/**
|
||||
* Click handler for sign out click
|
||||
*/
|
||||
onSignOutClick: (e: React.SyntheticEvent) => void;
|
||||
/**
|
||||
* Click handler for switch directory click
|
||||
*/
|
||||
onSwitchDirectoryClick: (e: React.SyntheticEvent) => void;
|
||||
}
|
||||
|
||||
export interface MeControlUser {
|
||||
/**
|
||||
* Display name for user
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Display email for user
|
||||
*/
|
||||
email: string;
|
||||
/**
|
||||
* Display tenant for user
|
||||
*/
|
||||
tenantName: string;
|
||||
/**
|
||||
* image source for the profic photo
|
||||
*/
|
||||
imageUrl: string;
|
||||
}
|
||||
|
||||
export class MeControlComponent extends React.Component<MeControlComponentProps> {
|
||||
public render(): JSX.Element {
|
||||
return this.props.isUserSignedIn ? this._renderProfileComponent() : this._renderSignInComponent();
|
||||
}
|
||||
|
||||
private _renderProfileComponent(): JSX.Element {
|
||||
const { user } = this.props;
|
||||
|
||||
const menuProps: IContextualMenuProps = {
|
||||
className: "mecontrolContextualMenu",
|
||||
isBeakVisible: false,
|
||||
directionalHintFixed: true,
|
||||
directionalHint: DirectionalHint.bottomRightEdge,
|
||||
calloutProps: {
|
||||
minPagePadding: 0
|
||||
},
|
||||
items: [
|
||||
{
|
||||
key: "Persona",
|
||||
onRender: this._renderPersonaComponent
|
||||
},
|
||||
{
|
||||
key: "SwitchDirectory",
|
||||
onRender: this._renderSwitchDirectory
|
||||
},
|
||||
{
|
||||
key: "SignOut",
|
||||
onRender: this._renderSignOut
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
const personaProps: IPersonaSharedProps = {
|
||||
imageUrl: user.imageUrl,
|
||||
text: user.email,
|
||||
secondaryText: user.tenantName,
|
||||
showSecondaryText: true,
|
||||
showInitialsUntilImageLoads: true,
|
||||
initialsColor: PersonaInitialsColor.teal,
|
||||
size: PersonaSize.size28,
|
||||
className: "mecontrolHeaderPersona"
|
||||
};
|
||||
|
||||
const buttonProps: IButtonProps = {
|
||||
id: "mecontrolHeader",
|
||||
className: "mecontrolHeaderButton",
|
||||
menuProps: menuProps,
|
||||
onRenderMenuIcon: () => <span />,
|
||||
styles: {
|
||||
rootHovered: { backgroundColor: "#393939" },
|
||||
rootFocused: { backgroundColor: "#393939" },
|
||||
rootPressed: { backgroundColor: "#393939" },
|
||||
rootExpanded: { backgroundColor: "#393939" }
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<FocusZone>
|
||||
<DefaultButton {...buttonProps}>
|
||||
<Persona {...personaProps} />
|
||||
</DefaultButton>
|
||||
</FocusZone>
|
||||
);
|
||||
}
|
||||
|
||||
private _renderPersonaComponent = (): JSX.Element => {
|
||||
const { user } = this.props;
|
||||
const personaProps: IPersonaSharedProps = {
|
||||
imageUrl: user.imageUrl,
|
||||
text: user.name,
|
||||
secondaryText: user.email,
|
||||
showSecondaryText: true,
|
||||
showInitialsUntilImageLoads: true,
|
||||
initialsColor: PersonaInitialsColor.teal,
|
||||
size: PersonaSize.size72,
|
||||
className: "mecontrolContextualMenuPersona"
|
||||
};
|
||||
|
||||
return <Persona {...personaProps} />;
|
||||
};
|
||||
|
||||
private _renderSwitchDirectory = (): JSX.Element => {
|
||||
return (
|
||||
<div
|
||||
className="switchDirectoryLink"
|
||||
onClick={(e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) =>
|
||||
this.props.onSwitchDirectoryClick(e)
|
||||
}
|
||||
>
|
||||
Switch Directory
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
private _renderSignOut = (): JSX.Element => {
|
||||
return (
|
||||
<div
|
||||
className="signOutLink"
|
||||
onClick={(e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>) => this.props.onSignOutClick(e)}
|
||||
>
|
||||
Sign out
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
private _renderSignInComponent = (): JSX.Element => {
|
||||
const buttonProps: IButtonProps = {
|
||||
className: "mecontrolSigninButton",
|
||||
text: "Sign In",
|
||||
onClick: (e: React.MouseEvent<BaseButton>) => this.props.onSignInClick(e),
|
||||
styles: {
|
||||
rootHovered: { backgroundColor: "#393939", color: "#fff" },
|
||||
rootFocused: { backgroundColor: "#393939", color: "#fff" },
|
||||
rootPressed: { backgroundColor: "#393939", color: "#fff" }
|
||||
}
|
||||
};
|
||||
return <DefaultButton {...buttonProps} />;
|
||||
};
|
||||
}
|
||||
@@ -1,16 +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 React from "react";
|
||||
import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
||||
import { MeControlComponent, MeControlComponentProps } from "./MeControlComponent";
|
||||
|
||||
export class MeControlComponentAdapter implements ReactAdapter {
|
||||
public parameters: ko.Observable<MeControlComponentProps>;
|
||||
|
||||
public renderComponent(): JSX.Element {
|
||||
return <MeControlComponent {...this.parameters()} />;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`test render renders not signed in 1`] = `
|
||||
<CustomizedDefaultButton
|
||||
className="mecontrolSigninButton"
|
||||
onClick={[Function]}
|
||||
styles={
|
||||
Object {
|
||||
"rootFocused": Object {
|
||||
"backgroundColor": "#393939",
|
||||
"color": "#fff",
|
||||
},
|
||||
"rootHovered": Object {
|
||||
"backgroundColor": "#393939",
|
||||
"color": "#fff",
|
||||
},
|
||||
"rootPressed": Object {
|
||||
"backgroundColor": "#393939",
|
||||
"color": "#fff",
|
||||
},
|
||||
}
|
||||
}
|
||||
text="Sign In"
|
||||
/>
|
||||
`;
|
||||
|
||||
exports[`test render renders signed in with full info 1`] = `
|
||||
<FocusZone
|
||||
direction={2}
|
||||
isCircularNavigation={false}
|
||||
shouldRaiseClicks={true}
|
||||
>
|
||||
<CustomizedDefaultButton
|
||||
className="mecontrolHeaderButton"
|
||||
id="mecontrolHeader"
|
||||
menuProps={
|
||||
Object {
|
||||
"calloutProps": Object {
|
||||
"minPagePadding": 0,
|
||||
},
|
||||
"className": "mecontrolContextualMenu",
|
||||
"directionalHint": 6,
|
||||
"directionalHintFixed": true,
|
||||
"isBeakVisible": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"key": "Persona",
|
||||
"onRender": [Function],
|
||||
},
|
||||
Object {
|
||||
"key": "SwitchDirectory",
|
||||
"onRender": [Function],
|
||||
},
|
||||
Object {
|
||||
"key": "SignOut",
|
||||
"onRender": [Function],
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
onRenderMenuIcon={[Function]}
|
||||
styles={
|
||||
Object {
|
||||
"rootExpanded": Object {
|
||||
"backgroundColor": "#393939",
|
||||
},
|
||||
"rootFocused": Object {
|
||||
"backgroundColor": "#393939",
|
||||
},
|
||||
"rootHovered": Object {
|
||||
"backgroundColor": "#393939",
|
||||
},
|
||||
"rootPressed": Object {
|
||||
"backgroundColor": "#393939",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<StyledPersonaBase
|
||||
className="mecontrolHeaderPersona"
|
||||
imageUrl="../../../../images/dotnet.png"
|
||||
initialsColor={3}
|
||||
secondaryText="Contoso"
|
||||
showInitialsUntilImageLoads={true}
|
||||
showSecondaryText={true}
|
||||
size={7}
|
||||
text="testuser@contoso.com"
|
||||
/>
|
||||
</CustomizedDefaultButton>
|
||||
</FocusZone>
|
||||
`;
|
||||
Reference in New Issue
Block a user