diff --git a/.env b/.env
index c6891804e8..3323e230fd 100644
--- a/.env
+++ b/.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=.
\ No newline at end of file
+# Failed to load resource: net::ERR_FILE_NOT_FOUND /favicon.ico:1
+PUBLIC_URL=.
diff --git a/config/webpack.common.js b/config/webpack.common.js
index 93eee8643e..cf19765e68 100644
--- a/config/webpack.common.js
+++ b/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")
- }
-};
\ No newline at end of file
+ ]
+ },
+ resolve: {
+ extensions: [".ts", ".js"]
+ },
+ output: {
+ filename: "main.js",
+ path: path.resolve(__dirname, "../build")
+ }
+};
diff --git a/package.json b/package.json
index 2a95feea9a..afd86a981d 100644
--- a/package.json
+++ b/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": {
diff --git a/src/App.test.tsx b/src/App.test.tsx
index d19b0729c0..53fa3907da 100644
--- a/src/App.test.tsx
+++ b/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(
-
-
- , div);
- ReactDOM.unmountComponentAtNode(div);
+ function createComponent() {
+ return mount(
+
+
+ ,
+ );
+ }
+
+ 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);
+ });
});
diff --git a/src/App.tsx b/src/App.tsx
index 79a299b99b..b2df5eac14 100644
--- a/src/App.tsx
+++ b/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";
diff --git a/src/electron/main.ts b/src/electron/main.ts
index 792af6ca20..48208dc440 100644
--- a/src/electron/main.ts
+++ b/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";
@@ -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
@@ -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();
}
/**
diff --git a/src/react/components/pages/homepage/homePage.test.tsx b/src/react/components/pages/homepage/homePage.test.tsx
index 658b176cf5..70b73c170a 100644
--- a/src/react/components/pages/homepage/homePage.test.tsx
+++ b/src/react/components/pages/homepage/homePage.test.tsx
@@ -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";
@@ -19,13 +19,13 @@ jest.mock("../../../../services/projectService");
describe("Homepage Component", () => {
let store: Store = 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(
@@ -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;
+ const homePage = wrapper.find(HomePage).childAt(0) as ReactWrapper;
if (homePage.props().recentProjects && homePage.props().recentProjects.length > 0) {
expect(wrapper.find(CondensedList).exists()).toBeTruthy();
}
@@ -99,7 +99,7 @@ describe("Homepage Component", () => {
await MockFactory.flushUi();
wrapper.update();
- const homePage = wrapper.find(HomePage).childAt(0) as ReactWrapper;
+ const homePage = wrapper.find(HomePage).childAt(0) as ReactWrapper;
expect(deleteProjectSpy).toBeCalledWith(recentProjects[0]);
expect(homePage.props().recentProjects.length).toEqual(recentProjects.length - 1);
@@ -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;
- homepage.find("a.new-project").simulate("click");
+ const eventMock = {
+ preventDefault: jest.fn(),
+ };
+
+ const homepage = wrapper.find(HomePage).childAt(0) as ReactWrapper;
+ 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(),
diff --git a/src/react/components/pages/homepage/homePage.tsx b/src/react/components/pages/homepage/homePage.tsx
index f26a8948cd..0b95e7a7fc 100644
--- a/src/react/components/pages/homepage/homePage.tsx
+++ b/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";
@@ -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 {
+export interface IHomePageProps extends RouteComponentProps, React.Props {
recentProjects: IProject[];
connections: IConnection[];
actions: IProjectActions;
}
-export interface IHomepageState {
+export interface IHomePageState {
cloudPickerOpen: boolean;
}
@@ -40,8 +40,8 @@ function mapDispatchToProps(dispatch) {
}
@connect(mapStateToProps, mapDispatchToProps)
-export default class HomePage extends React.Component {
- public state: IHomepageState = {
+export default class HomePage extends React.Component {
+ public state: IHomePageState = {
cloudPickerOpen: false,
};
@@ -103,9 +103,11 @@ export default class HomePage extends React.Component {
);
}
- private createNewProject = () => {
+ private createNewProject = (e: SyntheticEvent) => {
this.props.actions.closeProject();
this.props.history.push("/projects/create");
+
+ e.preventDefault();
}
private handleOpenCloudProjectClick = () => {
diff --git a/src/react/components/shell/mainContentRouter.test.tsx b/src/react/components/shell/mainContentRouter.test.tsx
index c09d2f11b2..876336c257 100644
--- a/src/react/components/shell/mainContentRouter.test.tsx
+++ b/src/react/components/shell/mainContentRouter.test.tsx
@@ -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";
@@ -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(
@@ -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 {