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:
Steve Faulkner
2021-01-19 16:31:55 -06:00
committed by GitHub
parent 8c40df0fa1
commit 2b2de7c645
79 changed files with 2250 additions and 6025 deletions

View File

@@ -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();
});
});

View File

@@ -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} />;
};
}

View File

@@ -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()} />;
}
}

View File

@@ -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>
`;