Skip to content
This repository has been archived by the owner on Dec 7, 2021. It is now read-only.

Commit

Permalink
fix: Fixes issue where user is unable to navigate to new project scre…
Browse files Browse the repository at this point in the history
…en (#629)

Resolves the issue where user is unable to navigate to new project screen from the homepage. This also addresses other strange behavior related to routing in the app.

-User being navigated to the homepage after creating a connection
-Refresh application button not working

Resolves AB#17258, 17263, 17058
  • Loading branch information
wbreza committed Mar 1, 2019
1 parent 886d5e5 commit 345dbbd
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 75 deletions.
6 changes: 3 additions & 3 deletions .env
@@ -1,5 +1,5 @@
# react-scripts build use this to generate the right path for assets
# react-scripts build use this to generate the right path for assets
# relative to index.html
# without it, you'll see error like this
# Failed to load resource: net::ERR_FILE_NOT_FOUND /favicon.ico:1
PUBLIC_URL=.
# Failed to load resource: net::ERR_FILE_NOT_FOUND /favicon.ico:1
PUBLIC_URL=.
53 changes: 28 additions & 25 deletions config/webpack.common.js
@@ -1,29 +1,32 @@
const path = require("path");

module.exports = {
target: "electron-main",
entry: "./src/electron/main.ts",
module: {
rules: [
{
test: /\.ts?$/,
use: [{
loader: "ts-loader",
options: {
compilerOptions: {
noEmit: false
node: {
__dirname: false,
},
target: "electron-main",
entry: "./src/electron/main.ts",
module: {
rules: [
{
test: /\.ts?$/,
use: [{
loader: "ts-loader",
options: {
compilerOptions: {
noEmit: false
}
}
}],
exclude: /node_modules/
}
}
}],
exclude: /node_modules/
}
]
},
resolve: {
extensions: [".ts", ".js"]
},
output: {
filename: "main.js",
path: path.resolve(__dirname, "../build")
}
};
]
},
resolve: {
extensions: [".ts", ".js"]
},
output: {
filename: "main.js",
path: path.resolve(__dirname, "../build")
}
};
4 changes: 4 additions & 0 deletions package.json
@@ -1,6 +1,10 @@
{
"name": "vott",
"version": "2.0.0-preview.1",
"author": {
"name": "Microsoft",
"url": "https://github.com/Microsoft/VoTT"
},
"description": "Visual Object Tagging Tool (VoTT) - an annotation and labeling tool for images and video.",
"homepage": "https://github.com/Microsoft/VoTT",
"repository": {
Expand Down
31 changes: 23 additions & 8 deletions src/App.test.tsx
@@ -1,19 +1,34 @@
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { Provider } from "react-redux";
import createReduxStore from "./redux/store/store";
import initialState from "./redux/store/initialState";
import { IApplicationState } from "./models//applicationState";
import { mount } from "enzyme";
import { HashRouter } from "react-router-dom";
import { KeyboardManager } from "./react/components/common/keyboardManager/keyboardManager";
import { ErrorHandler } from "./react/components/common/errorHandler/errorHandler";

it("renders without crashing", () => {
describe("App Component", () => {
const defaultState: IApplicationState = initialState;
const store = createReduxStore(defaultState);
const div = document.createElement("div");

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, div);
ReactDOM.unmountComponentAtNode(div);
function createComponent() {
return mount(
<Provider store={store}>
<App />
</Provider>,
);
}

it("renders without crashing", () => {
createComponent();
});

it("renders required top level components", () => {
const wrapper = createComponent();
expect(wrapper.find(HashRouter).exists()).toBe(true);
expect(wrapper.find(KeyboardManager).exists()).toEqual(true);
expect(wrapper.find(ErrorHandler).exists()).toEqual(true);
});
});
4 changes: 2 additions & 2 deletions src/App.tsx
@@ -1,11 +1,11 @@
import React, { Fragment } from "react";
import { connect } from "react-redux";
import { BrowserRouter as Router } from "react-router-dom";
import { HashRouter as Router } from "react-router-dom";
import { ToastContainer } from "react-toastify";
import Navbar from "./react/components/shell/navbar";
import Sidebar from "./react/components/shell/sidebar";
import MainContentRouter from "./react/components/shell/mainContentRouter";
import { IAppError, IApplicationState, IProject, AppError, ErrorCode } from "./models/applicationState";
import { IAppError, IApplicationState, IProject, ErrorCode } from "./models/applicationState";
import "./App.scss";
import "react-toastify/dist/ReactToastify.css";
import IAppErrorActions, * as appErrorActions from "./redux/actions/appErrorActions";
Expand Down
25 changes: 7 additions & 18 deletions src/electron/main.ts
@@ -1,4 +1,4 @@
import { app, ipcMain, BrowserWindow, dialog, BrowserWindowConstructorOptions, Menu } from "electron";
import { app, ipcMain, BrowserWindow, BrowserWindowConstructorOptions, Menu } from "electron";
import { IpcMainProxy } from "./common/ipcMainProxy";
import LocalFileSystem from "./providers/storage/localFileSystem";

Expand All @@ -8,28 +8,21 @@ let mainWindow: BrowserWindow;
let ipcMainProxy: IpcMainProxy;

function createWindow() {
// and load the index.html of the app.

const windowOptions: BrowserWindowConstructorOptions = {
width: 1024,
height: 768,
};
// Create the browser window.

const staticUrl = process.env.ELECTRON_START_URL || `file:///${__dirname}/index.html`;
if (process.env.ELECTRON_START_URL) {
// Disable web security to support loading in local file system resources
// TODO: Look into defined local security policy
windowOptions.webPreferences = {
webSecurity: false,
};
mainWindow = new BrowserWindow(windowOptions);
mainWindow.loadURL(process.env.ELECTRON_START_URL);
} else {
// When running in production mode or with static files use loadFile api vs. loadUrl api.
mainWindow = new BrowserWindow(windowOptions);
mainWindow.loadFile("build/index.html");
}

mainWindow = new BrowserWindow(windowOptions);
mainWindow.loadURL(staticUrl);

// Emitted when the window is closed.
mainWindow.on("closed", () => {
// Dereference the window object, usually you would store windows
Expand All @@ -53,12 +46,8 @@ function onReloadApp() {
return true;
}

function onToggleDevTools(sender: any, show: boolean) {
if (show) {
mainWindow.webContents.openDevTools();
} else {
mainWindow.webContents.closeDevTools();
}
function onToggleDevTools() {
mainWindow.webContents.toggleDevTools();
}

/**
Expand Down
21 changes: 13 additions & 8 deletions src/react/components/pages/homepage/homePage.test.tsx
Expand Up @@ -10,7 +10,7 @@ import createReduxStore from "../../../../redux/store/store";
import ProjectService from "../../../../services/projectService";
import CondensedList from "../../common/condensedList/condensedList";
import FilePicker, { IFilePickerProps } from "../../common/filePicker/filePicker";
import HomePage, { IHomepageProps, IHomepageState } from "./homePage";
import HomePage, { IHomePageProps, IHomePageState } from "./homePage";

jest.mock("../../common/cloudFilePicker/cloudFilePicker");
import { CloudFilePicker, ICloudFilePickerProps } from "../../common/cloudFilePicker/cloudFilePicker";
Expand All @@ -19,13 +19,13 @@ jest.mock("../../../../services/projectService");

describe("Homepage Component", () => {
let store: Store<IApplicationState> = null;
let props: IHomepageProps = null;
let props: IHomePageProps = null;
let wrapper: ReactWrapper = null;
let deleteProjectSpy: jest.SpyInstance = null;
let closeProjectSpy: jest.SpyInstance = null;
const recentProjects = MockFactory.createTestProjects(2);

function createComponent(store, props: IHomepageProps): ReactWrapper {
function createComponent(store, props: IHomePageProps): ReactWrapper {
return mount(
<Provider store={store}>
<Router>
Expand Down Expand Up @@ -79,7 +79,7 @@ describe("Homepage Component", () => {

it("should render a list of recent projects", () => {
expect(wrapper).not.toBeNull();
const homePage = wrapper.find(HomePage).childAt(0) as ReactWrapper<IHomepageProps>;
const homePage = wrapper.find(HomePage).childAt(0) as ReactWrapper<IHomePageProps>;
if (homePage.props().recentProjects && homePage.props().recentProjects.length > 0) {
expect(wrapper.find(CondensedList).exists()).toBeTruthy();
}
Expand All @@ -99,7 +99,7 @@ describe("Homepage Component", () => {
await MockFactory.flushUi();
wrapper.update();

const homePage = wrapper.find(HomePage).childAt(0) as ReactWrapper<IHomepageProps>;
const homePage = wrapper.find(HomePage).childAt(0) as ReactWrapper<IHomePageProps>;

expect(deleteProjectSpy).toBeCalledWith(recentProjects[0]);
expect(homePage.props().recentProjects.length).toEqual(recentProjects.length - 1);
Expand Down Expand Up @@ -148,13 +148,18 @@ describe("Homepage Component", () => {
});

it("closes any open project and navigates to the new project screen", () => {
const homepage = wrapper.find(HomePage).childAt(0) as ReactWrapper<IHomepageProps, IHomepageState>;
homepage.find("a.new-project").simulate("click");
const eventMock = {
preventDefault: jest.fn(),
};

const homepage = wrapper.find(HomePage).childAt(0) as ReactWrapper<IHomePageProps, IHomePageState>;
homepage.find("a.new-project").simulate("click", eventMock);
expect(closeProjectSpy).toBeCalled();
expect(homepage.props().history.push).toBeCalledWith("/projects/create");
expect(eventMock.preventDefault).toBeCalled();
});

function createProps(): IHomepageProps {
function createProps(): IHomePageProps {
return {
recentProjects: [],
connections: MockFactory.createTestConnections(),
Expand Down
18 changes: 10 additions & 8 deletions src/react/components/pages/homepage/homePage.tsx
@@ -1,6 +1,6 @@
import React from "react";
import React, { SyntheticEvent } from "react";
import { connect } from "react-redux";
import { Link, RouteComponentProps } from "react-router-dom";
import { RouteComponentProps } from "react-router-dom";
import { bindActionCreators } from "redux";
import { strings } from "../../../../common/strings";
import IProjectActions, * as projectActions from "../../../../redux/actions/projectActions";
Expand All @@ -13,16 +13,16 @@ import RecentProjectItem from "./recentProjectItem";
import { constants } from "../../../../common/constants";
import {
IApplicationState, IConnection, IProject,
ErrorCode, AppError, IAppError,
ErrorCode, AppError,
} from "../../../../models/applicationState";

export interface IHomepageProps extends RouteComponentProps, React.Props<HomePage> {
export interface IHomePageProps extends RouteComponentProps, React.Props<HomePage> {
recentProjects: IProject[];
connections: IConnection[];
actions: IProjectActions;
}

export interface IHomepageState {
export interface IHomePageState {
cloudPickerOpen: boolean;
}

Expand All @@ -40,8 +40,8 @@ function mapDispatchToProps(dispatch) {
}

@connect(mapStateToProps, mapDispatchToProps)
export default class HomePage extends React.Component<IHomepageProps> {
public state: IHomepageState = {
export default class HomePage extends React.Component<IHomePageProps, IHomePageState> {
public state: IHomePageState = {
cloudPickerOpen: false,
};

Expand Down Expand Up @@ -103,9 +103,11 @@ export default class HomePage extends React.Component<IHomepageProps> {
);
}

private createNewProject = () => {
private createNewProject = (e: SyntheticEvent) => {
this.props.actions.closeProject();
this.props.history.push("/projects/create");

e.preventDefault();
}

private handleOpenCloudProjectClick = () => {
Expand Down
6 changes: 3 additions & 3 deletions src/react/components/shell/mainContentRouter.test.tsx
Expand Up @@ -8,7 +8,7 @@ import { AnyAction, Store } from "redux";
import createReduxStore from "../../../redux/store/store";

import MainContentRouter from "./mainContentRouter";
import HomePage, { IHomepageProps } from "./../pages/homepage/homePage";
import HomePage, { IHomePageProps } from "./../pages/homepage/homePage";
import SettingsPage from "./../pages/appSettings/appSettingsPage";
import ConnectionsPage from "./../pages/connections/connectionsPage";
import ProfilePage from "./../pages/profileSettingsPage";
Expand All @@ -17,7 +17,7 @@ import { IApplicationState } from "./../../../models/applicationState";
describe("Main Content Router", () => {
const badRoute: string = "/index.html";

function createComponent(routerContext, route, store, props: IHomepageProps): ReactWrapper {
function createComponent(routerContext, route, store, props: IHomePageProps): ReactWrapper {
return mount(
<Provider store={store}>
<Router location={route} context={routerContext}>
Expand Down Expand Up @@ -51,7 +51,7 @@ describe("Main Content Router", () => {

const homePage = wrapper.find(HomePage);
expect(homePage.find(".app-homepage").exists()).toEqual(true);
});
});
});

function createStore(state?: IApplicationState): Store<any, AnyAction> {
Expand Down

0 comments on commit 345dbbd

Please sign in to comment.