summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--provisioning/modules/pixelated/manifests/source.pp5
-rw-r--r--service/pixelated/assets/favicon.pngbin592 -> 0 bytes
-rw-r--r--service/pixelated/assets/index.html9
-rw-r--r--service/pixelated/assets/login.html36
-rw-r--r--service/pixelated/resources/__init__.py11
-rw-r--r--service/pixelated/resources/backup_account_resource.py4
-rw-r--r--service/pixelated/resources/login_resource.py16
-rw-r--r--service/pixelated/resources/root_resource.py19
-rw-r--r--service/test/functional/features/environment.py2
-rw-r--r--service/test/functional/features/steps/attachments.py10
-rw-r--r--service/test/functional/features/steps/common.py2
-rw-r--r--service/test/functional/features/steps/tag_list.py21
-rw-r--r--service/test/unit/resources/test_helpers.py7
-rw-r--r--service/test/unit/resources/test_login_resource.py53
-rw-r--r--web-ui/.eslintignore1
-rw-r--r--web-ui/app/images/hive-bg.png (renamed from service/pixelated/assets/hive-bg.png)bin3356 -> 3356 bytes
-rw-r--r--web-ui/app/images/logo-orange.svg (renamed from service/pixelated/assets/pixelated-logo-orange.svg)0
-rw-r--r--web-ui/app/index.html34
-rw-r--r--web-ui/app/js/page/default.js2
-rw-r--r--web-ui/app/sandbox.html2
-rw-r--r--web-ui/app/scss/base/_fonts.scss23
-rw-r--r--web-ui/config/copy-webpack.js88
-rw-r--r--web-ui/config/protected-assets-webpack.js25
-rw-r--r--web-ui/config/public-assets-webpack.js10
-rw-r--r--web-ui/src/backup_account/backup_account.html2
-rw-r--r--web-ui/src/backup_account/page.js2
-rw-r--r--web-ui/src/common/footer/footer.js2
-rw-r--r--web-ui/src/common/header/header.js2
-rw-r--r--web-ui/src/i18n.js2
-rw-r--r--web-ui/src/interstitial/interstitial.html (renamed from service/pixelated/assets/Interstitial.html)6
-rw-r--r--web-ui/src/interstitial/interstitial.js (renamed from service/pixelated/assets/Interstitial.js)2
-rw-r--r--web-ui/src/interstitial/jquery-2.1.3.min.js (renamed from service/pixelated/assets/jquery-2.1.3.min.js)0
-rw-r--r--web-ui/src/interstitial/snap.svg-min.js (renamed from service/pixelated/assets/snap.svg-min.js)0
-rw-r--r--web-ui/src/login/_login_disclaimer_banner.html (renamed from service/pixelated/assets/_login_disclaimer_banner.html)0
-rw-r--r--web-ui/src/login/app.js35
-rw-r--r--web-ui/src/login/login.css (renamed from service/pixelated/assets/pixelated.css)19
-rw-r--r--web-ui/src/login/login.html26
-rw-r--r--web-ui/src/login/login.js33
-rw-r--r--web-ui/src/login/normalize.min.css (renamed from service/pixelated/assets/normalize.min.css)0
-rw-r--r--web-ui/src/login/opensans.css (renamed from service/pixelated/assets/opensans.css)0
-rw-r--r--web-ui/webpack.config.js62
-rw-r--r--web-ui/webpack.production.config.js67
-rw-r--r--web-ui/webpack.test.config.js1
44 files changed, 376 insertions, 281 deletions
diff --git a/Makefile b/Makefile
index 1d7a2343..bca2cf91 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ VIRTUALENV=~/.venvs/pixua
.PHONY: setup requirements install requirements_py install_py requirements_js install_js create_virtualenv
.PHONY: test test_py test_js test_all linters linters_py linters_js coverage unit_tests_py unit_tests_js
-.PHONY: integration_tests_py functional_tests ensure_phantomjs_installed ensure_virtualenv_installed clean
+.PHONY: integration_tests_py functional_tests functional_tests_ci ensure_virtualenv_installed clean
.PHONY: clean_all clean_py clean_js clean_cache remove_virtualenv remove_javascript_packages
setup: install
@@ -73,16 +73,16 @@ integration_tests:
cd service;\
trial -j`grep -c "^processor" /proc/cpuinfo || sysctl -n hw.logicalcpu` --reporter=text test.integration
-functional_tests: clean requirements install ensure_phantomjs_installed
+functional_tests: clean requirements install
@. $(VIRTUALENV)/bin/activate;\
+ export PATH=$(PATH):/usr/lib/chromium/;\
cd service;\
- behave --tags ~@wip --tags ~@smoke test/functional/features
+ xvfb-run --server-args="-screen 0 1280x1024x24" behave --tags ~@wip --tags ~@smoke test/functional/features
-ensure_phantomjs_installed:
- @if [ ! `which phantomjs` ]; then\
- echo "You need phantomJS to run these tests";\
- exit 1;\
- fi
+functional_tests_ci: clean requirements install
+ @. $(VIRTUALENV)/bin/activate;\
+ cd service;\
+ behave --tags ~@wip --tags ~@smoke test/functional/features
ensure_virtualenv_installed:
@if [ ! `which virtualenv` ]; then\
diff --git a/provisioning/modules/pixelated/manifests/source.pp b/provisioning/modules/pixelated/manifests/source.pp
index 7dc3358f..4da0669f 100644
--- a/provisioning/modules/pixelated/manifests/source.pp
+++ b/provisioning/modules/pixelated/manifests/source.pp
@@ -13,7 +13,10 @@ class pixelated::source {
'libsqlcipher-dev',
'libfontconfig1',
'build-essential',
- 'ruby-compass']:
+ 'ruby-compass',
+ 'xvfb',
+ 'xauth',
+ 'chromedriver']:
ensure => latest
}
diff --git a/service/pixelated/assets/favicon.png b/service/pixelated/assets/favicon.png
deleted file mode 100644
index e14841c7..00000000
--- a/service/pixelated/assets/favicon.png
+++ /dev/null
Binary files differ
diff --git a/service/pixelated/assets/index.html b/service/pixelated/assets/index.html
deleted file mode 100644
index c095577e..00000000
--- a/service/pixelated/assets/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<html>
- <head>
- <meta http-equiv="refresh" content="0;URL=/login">
- </head>
- <body bgcolor="#FFFFFF" text="#000000\">
- <a href="/login">click here</a>
- </body>
-</html>
-
diff --git a/service/pixelated/assets/login.html b/service/pixelated/assets/login.html
deleted file mode 100644
index ff103f03..00000000
--- a/service/pixelated/assets/login.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE html>
-<html xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">
-<head>
- <title>Pixelated - Login</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <link rel="icon" type="image/png" href="/startup-assets/favicon.png" />
- <link rel="stylesheet" type="text/css" href="/startup-assets/normalize.min.css" />
- <link rel="stylesheet" type="text/css" href="/startup-assets/pixelated.css" />
- <link rel="stylesheet" type="text/css" href="/startup-assets/opensans.css" />
-</head>
-<body>
-<div class="content">
- <div class="login">
-
- <img class="logo" src="/startup-assets/pixelated-logo-orange.svg" alt="Pixelated logo"/>
-
- <p t:render="error_msg" class="error" ></p>
-
-
- <form class="standard" id="login_form" action="/login" method="post">
- <input type="text" name="username" id="email" class="text-field" placeholder="username" tabindex="1"
- autofocus="" />
- <input type="password" name="password" id="password" class="text-field" placeholder="password"
- tabindex="2" autocomplete="off" />
-
- <input type="submit" name="login" value="Login" class="button" tabindex="3" />
-
- </form>
- </div>
- <div class="disclaimer">
- <div t:render="disclaimer"></div>
- </div>
-</div>
-</body>
-
-</html>
diff --git a/service/pixelated/resources/__init__.py b/service/pixelated/resources/__init__.py
index 6bac2f59..f5512644 100644
--- a/service/pixelated/resources/__init__.py
+++ b/service/pixelated/resources/__init__.py
@@ -57,12 +57,15 @@ def handle_error_deferred(e, request):
request.finish()
-def get_startup_folder():
- path = os.path.dirname(os.path.abspath(__file__))
- return os.path.join(path, '..', 'assets')
+def get_protected_static_folder():
+ return os.path.join(_get_static_folder(), 'protected')
-def get_static_folder():
+def get_public_static_folder():
+ return os.path.join(_get_static_folder(), 'public')
+
+
+def _get_static_folder():
static_folder = os.path.abspath(os.path.join(os.path.abspath(__file__), "..", "..", "..", "..", "web-ui", "dist"))
if not os.path.exists(static_folder):
static_folder = os.path.join('/', 'usr', 'share', 'pixelated-user-agent')
diff --git a/service/pixelated/resources/backup_account_resource.py b/service/pixelated/resources/backup_account_resource.py
index 5d9cb032..f1eeee53 100644
--- a/service/pixelated/resources/backup_account_resource.py
+++ b/service/pixelated/resources/backup_account_resource.py
@@ -19,13 +19,13 @@ from xml.sax import SAXParseException
from pixelated.resources import BaseResource
from twisted.python.filepath import FilePath
-from pixelated.resources import get_static_folder
+from pixelated.resources import get_protected_static_folder
from twisted.web.http import OK
from twisted.web.template import Element, XMLFile, renderElement
class BackupAccountPage(Element):
- loader = XMLFile(FilePath(os.path.join(get_static_folder(), 'backup_account.html')))
+ loader = XMLFile(FilePath(os.path.join(get_protected_static_folder(), 'backup_account.html')))
def __init__(self):
super(BackupAccountPage, self).__init__()
diff --git a/service/pixelated/resources/login_resource.py b/service/pixelated/resources/login_resource.py
index 4bbceb89..bb05489e 100644
--- a/service/pixelated/resources/login_resource.py
+++ b/service/pixelated/resources/login_resource.py
@@ -20,7 +20,7 @@ from xml.sax import SAXParseException
from pixelated.authentication import Authenticator
from pixelated.config.leap import BootstrapUserServices
from pixelated.resources import BaseResource, UnAuthorizedResource, IPixelatedSession
-from pixelated.resources import get_startup_folder, respond_json
+from pixelated.resources import get_public_static_folder, respond_json
from twisted.cred.error import UnauthorizedLogin
from twisted.internet import defer
from twisted.logger import Logger
@@ -45,7 +45,7 @@ def parse_accept_language(all_headers):
class DisclaimerElement(Element):
- loader = XMLFile(FilePath(os.path.join(get_startup_folder(), '_login_disclaimer_banner.html')))
+ loader = XMLFile(FilePath(os.path.join(get_public_static_folder(), '_login_disclaimer_banner.html')))
def __init__(self, banner):
super(DisclaimerElement, self).__init__()
@@ -68,7 +68,7 @@ class DisclaimerElement(Element):
class LoginWebSite(Element):
- loader = XMLFile(FilePath(os.path.join(get_startup_folder(), 'login.html')))
+ loader = XMLFile(FilePath(os.path.join(get_public_static_folder(), 'login.html')))
def __init__(self, error_msg=None, disclaimer_banner_file=None):
super(LoginWebSite, self).__init__()
@@ -91,14 +91,14 @@ class LoginResource(BaseResource):
def __init__(self, services_factory, provider=None, disclaimer_banner=None, authenticator=None):
BaseResource.__init__(self, services_factory)
- self._startup_folder = get_startup_folder()
self._disclaimer_banner = disclaimer_banner
self._provider = provider
self._authenticator = authenticator or Authenticator(provider)
self._bootstrap_user_services = BootstrapUserServices(services_factory, provider)
- self.putChild('startup-assets', File(self._startup_folder))
- with open(os.path.join(self._startup_folder, 'Interstitial.html')) as f:
+ static_folder = get_public_static_folder()
+ self.putChild('public', File(static_folder))
+ with open(os.path.join(static_folder, 'interstitial.html')) as f:
self.interstitial = f.read()
def getChild(self, path, request):
@@ -176,5 +176,7 @@ class LoginStatusResource(BaseResource):
def render_GET(self, request):
session = IPixelatedSession(request.getSession())
- response = {'status': str(session.check_login_status())}
+ status = 'completed' if self._services_factory.mode.is_single_user else str(session.check_login_status())
+
+ response = {'status': status}
return respond_json(response, request)
diff --git a/service/pixelated/resources/root_resource.py b/service/pixelated/resources/root_resource.py
index 206cb3be..320a1204 100644
--- a/service/pixelated/resources/root_resource.py
+++ b/service/pixelated/resources/root_resource.py
@@ -20,14 +20,14 @@ from string import Template
from pixelated.resources.users import UsersResource
from pixelated.resources import BaseResource, UnAuthorizedResource, UnavailableResource
-from pixelated.resources import get_startup_folder, get_static_folder
+from pixelated.resources import get_public_static_folder, get_protected_static_folder
from pixelated.resources.attachments_resource import AttachmentsResource
from pixelated.resources.sandbox_resource import SandboxResource
from pixelated.resources.backup_account_resource import BackupAccountResource
from pixelated.resources.contacts_resource import ContactsResource
from pixelated.resources.features_resource import FeaturesResource
from pixelated.resources.feedback_resource import FeedbackResource
-from pixelated.resources.login_resource import LoginResource
+from pixelated.resources.login_resource import LoginResource, LoginStatusResource
from pixelated.resources.logout_resource import LogoutResource
from pixelated.resources.user_settings_resource import UserSettingsResource
from pixelated.resources.mail_resource import MailResource
@@ -51,17 +51,18 @@ MODE_RUNNING = 2
class RootResource(BaseResource):
def __init__(self, services_factory):
BaseResource.__init__(self, services_factory)
- self._startup_assets_folder = get_startup_folder()
- self._static_folder = get_static_folder()
- self._html_template = open(os.path.join(self._static_folder, 'index.html')).read()
+ self._public_static_folder = get_public_static_folder()
+ self._protected_static_folder = get_protected_static_folder()
+ self._html_template = open(os.path.join(self._protected_static_folder, 'index.html')).read()
self._services_factory = services_factory
self._child_resources = ChildResourcesMap()
- with open(os.path.join(self._startup_assets_folder, 'Interstitial.html')) as f:
+ with open(os.path.join(self._public_static_folder, 'interstitial.html')) as f:
self.interstitial = f.read()
self._startup_mode()
def _startup_mode(self):
- self.putChild('startup-assets', File(self._startup_assets_folder))
+ self.putChild('public', File(self._public_static_folder))
+ self.putChild('status', LoginStatusResource(self._services_factory))
self._mode = MODE_STARTUP
def getChild(self, path, request):
@@ -89,9 +90,9 @@ class RootResource(BaseResource):
return csrf_input and csrf_input == xsrf_token
def initialize(self, provider=None, disclaimer_banner=None, authenticator=None):
+ self._child_resources.add('assets', File(self._protected_static_folder))
self._child_resources.add('backup-account', BackupAccountResource(self._services_factory))
- self._child_resources.add('sandbox', SandboxResource(self._static_folder))
- self._child_resources.add('assets', File(self._static_folder))
+ self._child_resources.add('sandbox', SandboxResource(self._protected_static_folder))
self._child_resources.add('keys', KeysResource(self._services_factory))
self._child_resources.add(AttachmentsResource.BASE_URL, AttachmentsResource(self._services_factory))
self._child_resources.add('contacts', ContactsResource(self._services_factory))
diff --git a/service/test/functional/features/environment.py b/service/test/functional/features/environment.py
index d49016b6..821a762b 100644
--- a/service/test/functional/features/environment.py
+++ b/service/test/functional/features/environment.py
@@ -63,7 +63,7 @@ def before_all(context):
def _setup_webdriver(context):
- browser = context.config.userdata.get('webdriver', 'phantomjs')
+ browser = context.config.userdata.get('webdriver', 'chrome')
supported_webdrivers = {
'phantomjs': webdriver.PhantomJS,
'firefox': webdriver.Firefox,
diff --git a/service/test/functional/features/steps/attachments.py b/service/test/functional/features/steps/attachments.py
index 8852b787..37fabb6a 100644
--- a/service/test/functional/features/steps/attachments.py
+++ b/service/test/functional/features/steps/attachments.py
@@ -13,6 +13,8 @@
#
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+import os
+
from email.MIMEMultipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.mime.text import MIMEText
@@ -67,8 +69,10 @@ def find_icon(context):
def upload_big_file(context):
base_dir = "test/functional/features/files/"
fname = "over_5mb.data"
+ path = os.path.abspath(os.path.join(base_dir, fname))
+
context.browser.execute_script("$('#fileupload').removeAttr('hidden');")
- fill_by_css_selector(context, '#fileupload', base_dir + fname)
+ fill_by_css_selector(context, '#fileupload', path)
find_element_by_css_selector(context, '#upload-error-message')
@@ -97,7 +101,9 @@ def should_not_show_upload_error_message(context):
def upload_attachment(context):
base_dir = "test/functional/features/files/"
fname = "5mb.data"
- fill_by_css_selector(context, '#fileupload', base_dir + fname)
+ path = os.path.abspath(os.path.join(base_dir, fname))
+
+ fill_by_css_selector(context, '#fileupload', path)
attachment_list_item = find_element_by_css_selector(context, '#attachment-list-item li a')
assert attachment_list_item.text == "%s (5.00 Mb)" % fname
diff --git a/service/test/functional/features/steps/common.py b/service/test/functional/features/steps/common.py
index edfe2a50..3e1e995e 100644
--- a/service/test/functional/features/steps/common.py
+++ b/service/test/functional/features/steps/common.py
@@ -61,7 +61,7 @@ def _wait_until_elements_are_visible_by_locator(context, locator_tuple, timeout=
def _wait_until_element_is_visible_by_locator(context, locator_tuple, timeout=TIMEOUT_IN_S):
wait = WebDriverWait(context.browser, timeout)
- wait.until(EC.presence_of_element_located(locator_tuple))
+ wait.until(EC.visibility_of_element_located(locator_tuple))
return context.browser.find_element(locator_tuple[0], locator_tuple[1])
diff --git a/service/test/functional/features/steps/tag_list.py b/service/test/functional/features/steps/tag_list.py
index daea416d..e3382a61 100644
--- a/service/test/functional/features/steps/tag_list.py
+++ b/service/test/functional/features/steps/tag_list.py
@@ -14,11 +14,10 @@
# You should have received a copy of the GNU Affero General Public License
# along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
from behave import when
-from selenium.common.exceptions import TimeoutException
+from selenium.common.exceptions import TimeoutException, StaleElementReferenceException
from common import (
find_element_by_class_name,
- find_element_by_id,
find_element_by_css_selector,
wait_for_user_alert_to_disapear)
@@ -37,12 +36,11 @@ def expand_side_nav(context):
if is_side_nav_expanded(context):
return
- toggle = find_element_by_class_name(context, 'side-nav-toggle')
- toggle.click()
+ find_element_by_css_selector(context, '.side-nav-toggle-icon i').click()
@when('I select the tag \'{tag}\'')
-def impl(context, tag):
+def select_tag(context, tag):
wait_for_user_alert_to_disapear(context)
expand_side_nav(context)
@@ -53,23 +51,14 @@ def impl(context, tag):
try:
find_element_by_css_selector(context, '#tag-%s' % tag)
- e = find_element_by_id(context, 'tag-%s' % tag)
+ e = find_element_by_css_selector(context, '#tag-%s .tag-label' % tag)
e.click()
find_element_by_css_selector(context, ".mail-list-entry__item[href*='%s']" % tag)
success = True
- except TimeoutException:
+ except (TimeoutException, StaleElementReferenceException):
pass
finally:
try_again -= 1
assert success
-
-
-@when('I am in \'{tag}\'')
-def impl(context, tag):
- expand_side_nav(context)
-
- find_element_by_css_selector(context, '#tag-%s' % tag)
- e = find_element_by_id(context, 'tag-%s' % tag)
- assert "selected" in e.get_attribute("class")
diff --git a/service/test/unit/resources/test_helpers.py b/service/test/unit/resources/test_helpers.py
index e21c5373..6c456f51 100644
--- a/service/test/unit/resources/test_helpers.py
+++ b/service/test/unit/resources/test_helpers.py
@@ -18,6 +18,7 @@ from twisted.trial import unittest
import re
from pixelated.resources import respond_json, respond_json_deferred
+from pixelated.resources import get_public_static_folder, get_protected_static_folder
from test.unit.resources import DummySite
from twisted.web.test.requesthelper import DummyRequest
@@ -44,3 +45,9 @@ class TestHelpers(unittest.TestCase):
self.assertEqual(b"{\"test\": \"yep\"}", request.written[0])
self.assertEqual([b"application/json"],
request.responseHeaders.getRawHeaders("Content-Type"))
+
+ def test_getting_public_folder_returns_path(self):
+ self.assertIn('web-ui/dist/public', get_public_static_folder())
+
+ def test_getting_protected_folder_returns_path(self):
+ self.assertIn('web-ui/dist/protected', get_protected_static_folder())
diff --git a/service/test/unit/resources/test_login_resource.py b/service/test/unit/resources/test_login_resource.py
index 834b9710..bd0f9122 100644
--- a/service/test/unit/resources/test_login_resource.py
+++ b/service/test/unit/resources/test_login_resource.py
@@ -23,7 +23,7 @@ from twisted.internet import defer
from twisted.trial import unittest
from twisted.web.test.requesthelper import DummyRequest
-from pixelated.resources.login_resource import LoginResource
+from pixelated.resources.login_resource import LoginResource, LoginStatusResource
from pixelated.resources.login_resource import parse_accept_language
from test.unit.resources import DummySite
@@ -87,23 +87,15 @@ class TestLoginResource(unittest.TestCase):
d = self.web.get(request)
- def assert_form_rendered(_):
+ def assert_login_page_rendered(_):
self.assertEqual(200, request.responseCode)
- form_action = 'action="/login"'
- form_method = 'method="post"'
- input_username = 'name="username"'
- input_password = 'name="password"'
- input_submit = 'name="login"'
+ title = 'Pixelated - Login'
default_disclaimer = 'Some disclaimer'
written_response = ''.join(request.written)
- self.assertIn(form_action, written_response)
- self.assertIn(form_method, written_response)
- self.assertIn(input_password, written_response)
- self.assertIn(input_submit, written_response)
- self.assertIn(input_username, written_response)
+ self.assertIn(title, written_response)
self.assertIn(default_disclaimer, written_response)
- d.addCallback(assert_form_rendered)
+ d.addCallback(assert_login_page_rendered)
return d
def _write(self, filename, content):
@@ -238,7 +230,7 @@ class TestLoginPOST(unittest.TestCase):
def assert_interstitial_in_response(_):
mock_authenticate.assert_called_once_with(self.username, self.password)
- interstitial_js_in_template = '<script src="startup-assets/Interstitial.js"></script>'
+ interstitial_js_in_template = '<script src="/public/interstitial.js"></script>'
self.assertIn(interstitial_js_in_template, self.request.written[0])
d.addCallback(assert_interstitial_in_response)
@@ -314,3 +306,36 @@ class TestLoginPOST(unittest.TestCase):
d.addCallback(assert_login_error_called)
return d
+
+
+class TestLoginStatus(unittest.TestCase):
+ def setUp(self):
+ self.services_factory = mock()
+ self.resource = LoginStatusResource(self.services_factory)
+ self.web = DummySite(self.resource)
+
+ self.request = DummyRequest(['/status'])
+
+ def test_login_status_completed_when_single_user(self):
+ self.services_factory.mode = mock()
+ self.services_factory.mode.is_single_user = True
+ d = self.web.get(self.request)
+
+ def assert_login_completed(_):
+ self.assertIn('completed', self.request.written[0])
+
+ d.addCallback(assert_login_completed)
+ return d
+
+ @patch('pixelated.resources.session.PixelatedSession.check_login_status')
+ def test_login_status_when_multi_user_returns_check_login_status(self, mock_login_status):
+ self.services_factory.mode = mock()
+ self.services_factory.mode.is_single_user = False
+ mock_login_status.return_value = 'started'
+ d = self.web.get(self.request)
+
+ def assert_login_completed(_):
+ self.assertIn('started', self.request.written[0])
+
+ d.addCallback(assert_login_completed)
+ return d
diff --git a/web-ui/.eslintignore b/web-ui/.eslintignore
new file mode 100644
index 00000000..8cccef3c
--- /dev/null
+++ b/web-ui/.eslintignore
@@ -0,0 +1 @@
+src/interstitial
diff --git a/service/pixelated/assets/hive-bg.png b/web-ui/app/images/hive-bg.png
index 77316967..77316967 100644
--- a/service/pixelated/assets/hive-bg.png
+++ b/web-ui/app/images/hive-bg.png
Binary files differ
diff --git a/service/pixelated/assets/pixelated-logo-orange.svg b/web-ui/app/images/logo-orange.svg
index 7e0ef43d..7e0ef43d 100644
--- a/service/pixelated/assets/pixelated-logo-orange.svg
+++ b/web-ui/app/images/logo-orange.svg
diff --git a/web-ui/app/index.html b/web-ui/app/index.html
index b40aecdf..72b04c83 100644
--- a/web-ui/app/index.html
+++ b/web-ui/app/index.html
@@ -1,15 +1,15 @@
<!DOCTYPE html>
<html>
<head>
-<link rel="icon" type="image/png" href="assets/images/Favicon.png">
+<link rel="icon" type="image/png" href="public/images/Favicon.png">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>$account_email - Pixelated Mail</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
-<link href="assets/bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
-<link href="assets/bower_components/jquery-file-upload/css/jquery.fileupload.css" rel="stylesheet" type="text/css">
-<link rel="stylesheet" href="assets/css/style.css">
+<link href="/assets/css/font-awesome.min.css" rel="stylesheet" type="text/css">
+<link href="/assets/css/jquery.fileupload.css" rel="stylesheet" type="text/css">
+<link rel="stylesheet" href="/assets/css/style.css">
</head>
<body>
@@ -92,19 +92,19 @@
</div>
</div>
-<script src="assets/bower_components/modernizr/modernizr.js"></script>
-<script src="assets/bower_components/lodash/dist/lodash.min.js"></script>
-<script src="assets/bower_components/jquery/dist/jquery.min.js"></script>
-<script src="assets/bower_components/jquery-ui/jquery-ui.min.js"></script>
-<script src="assets/bower_components/jquery-file-upload/js/jquery.fileupload.js"></script>
-<script src="assets/bower_components/handlebars/handlebars.min.js"></script>
-<script src="assets/bower_components/typeahead.js/dist/typeahead.bundle.min.js"></script>
-<script src="assets/bower_components/iframe-resizer/js/iframeResizer.min.js"></script>
-<script src="assets/bower_components/foundation/js/foundation.js" ></script>
-<script src="assets/bower_components/foundation/js/foundation/foundation.reveal.js" ></script>
-<script src="assets/bower_components/foundation/js/foundation/foundation.offcanvas.js"></script>
-<script src="assets/js/foundation/initialize_foundation.js"></script>
-<script src="assets/app.js"></script>
+<script src="/assets/modernizr.js"></script>
+<script src="/assets/lodash.min.js"></script>
+<script src="/assets/jquery.min.js"></script>
+<script src="/assets/jquery-ui.min.js"></script>
+<script src="/assets/jquery.fileupload.js"></script>
+<script src="/assets/handlebars.min.js"></script>
+<script src="/assets/typeahead.bundle.min.js"></script>
+<script src="/assets/iframeResizer.min.js"></script>
+<script src="/assets/foundation.js" ></script>
+<script src="/assets/foundation.reveal.js" ></script>
+<script src="/assets/foundation.offcanvas.js"></script>
+<script src="/assets/initialize_foundation.js"></script>
+<script src="/assets/app.js"></script>
</body>
</html>
diff --git a/web-ui/app/js/page/default.js b/web-ui/app/js/page/default.js
index ecaedfd8..541bb4b7 100644
--- a/web-ui/app/js/page/default.js
+++ b/web-ui/app/js/page/default.js
@@ -96,7 +96,7 @@ define(
'use strict';
function initialize(path) {
- viewI18n.init(path + '/assets/');
+ viewI18n.init(path + '/public/');
viewI18n.loaded(function() {
paneContractExpand.attachTo(document);
diff --git a/web-ui/app/sandbox.html b/web-ui/app/sandbox.html
index 3e110977..52da1f5b 100644
--- a/web-ui/app/sandbox.html
+++ b/web-ui/app/sandbox.html
@@ -6,7 +6,7 @@
<link href="css/sandbox.css" rel="stylesheet" type="text/css">
<script src="sandbox.js"></script>
- <script src="bower_components/iframe-resizer/js/iframeResizer.contentWindow.min.js"></script>
+ <script src="/assets/iframeResizer.contentWindow.min.js"></script>
</head>
<body></body>
diff --git a/web-ui/app/scss/base/_fonts.scss b/web-ui/app/scss/base/_fonts.scss
index dfc56dd8..9a47b5ed 100644
--- a/web-ui/app/scss/base/_fonts.scss
+++ b/web-ui/app/scss/base/_fonts.scss
@@ -2,67 +2,66 @@
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
- src: local('Open Sans Light'), local('OpenSans-Light'), url('/assets/fonts/OpenSans-Light.woff') format('woff');
+ src: local('Open Sans Light'), local('OpenSans-Light'), url('/public/fonts/OpenSans-Light.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
- src: local('Open Sans'), local('OpenSans'), url('/assets/fonts/OpenSans.woff') format('woff');
+ src: local('Open Sans'), local('OpenSans'), url('/public/fonts/OpenSans.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
- src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/assets/fonts/OpenSans-Semibold.woff') format('woff');
+ src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url('/public/fonts/OpenSans-Semibold.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
- src: local('Open Sans Bold'), local('OpenSans-Bold'), url('/assets/fonts/OpenSans-Bold.woff') format('woff');
+ src: local('Open Sans Bold'), local('OpenSans-Bold'), url('/public/fonts/OpenSans-Bold.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 800;
- src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url('/assets/fonts/OpenSans-Extrabold.woff') format('woff');
+ src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url('/public/fonts/OpenSans-Extrabold.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 300;
- src: local('Open Sans Light Italic'), local('OpenSansLight-Italic'), url('/assets/fonts/OpenSansLight-Italic.woff') format('woff');
+ src: local('Open Sans Light Italic'), local('OpenSansLight-Italic'), url('/public/fonts/OpenSansLight-Italic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400;
- src: local('Open Sans Italic'), local('OpenSans-Italic'), url('/assets/fonts/OpenSans-Italic.woff') format('woff');
+ src: local('Open Sans Italic'), local('OpenSans-Italic'), url('/public/fonts/OpenSans-Italic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 600;
- src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('/assets/fonts/OpenSans-SemiboldItalic.woff') format('woff');
+ src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url('/public/fonts/OpenSans-SemiboldItalic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 700;
- src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('/assets/fonts/OpenSans-BoldItalic.woff') format('woff');
+ src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url('/public/fonts/OpenSans-BoldItalic.woff') format('woff');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 800;
- src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url('/assets/fonts/OpenSans-ExtraboldItalic.woff') format('woff');
+ src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url('/public/fonts/OpenSans-ExtraboldItalic.woff') format('woff');
}
@font-face {
font-family: 'icomoon';
font-style: normal;
font-weight: 400;
- src: url('/assets/fonts/icomoon.woff') format('woff'), url('/assets/fonts/icomoon.ttf') format('truetype'), ;
+ src: url('/public/fonts/icomoon.woff') format('woff'), url('/public/fonts/icomoon.ttf') format('truetype'), ;
}
-
diff --git a/web-ui/config/copy-webpack.js b/web-ui/config/copy-webpack.js
deleted file mode 100644
index 1f7f743a..00000000
--- a/web-ui/config/copy-webpack.js
+++ /dev/null
@@ -1,88 +0,0 @@
-var CopyWebpackPlugin = require('copy-webpack-plugin');
-
-module.exports = new CopyWebpackPlugin([
- { context: 'app/', from: '404.html' },
- { context: 'app/', from: 'index.html' },
- { context: 'app/', from: 'sandbox.html' },
- { context: 'src/backup_account/', from: 'backup_account.html' },
- { context: 'app/', from: 'css/*' },
- { context: 'app/', from: 'fonts/*' },
- { context: 'app/', from: 'locales/**/*' },
- { context: 'app/', from: 'images/**/*' },
- { context: 'app/', from: 'bower_components/font-awesome/fonts/*' },
- {
- context: 'app/',
- from: 'bower_components/font-awesome/css/font-awesome.min.css',
- to: 'bower_components/font-awesome/css'
- },
- {
- context: 'app/',
- from: 'bower_components/jquery-file-upload/css/jquery.fileupload.css',
- to: 'bower_components/jquery-file-upload/css'
- },
- {
- context: 'app/',
- from: 'bower_components/modernizr/modernizr.js',
- to: 'bower_components/modernizr'
- },
- {
- context: 'app/',
- from: 'bower_components/lodash/dist/lodash.min.js',
- to: 'bower_components/lodash/dist'
- },
- {
- context: 'app/',
- from: 'bower_components/jquery/dist/jquery.min.js',
- to: 'bower_components/jquery/dist'
- },
- {
- context: 'app/',
- from: 'bower_components/jquery-ui/jquery-ui.min.js',
- to: 'bower_components/jquery-ui'
- },
- {
- context: 'app/',
- from: 'bower_components/jquery-file-upload/js/jquery.fileupload.js',
- to: 'bower_components/jquery-file-upload/js'
- },
- {
- context: 'app/',
- from: 'bower_components/handlebars/handlebars.min.js',
- to: 'bower_components/handlebars'
- },
- {
- context: 'app/',
- from: 'bower_components/typeahead.js/dist/typeahead.bundle.min.js',
- to: 'bower_components/typeahead.js/dist'
- },
- {
- context: 'app/',
- from: 'bower_components/iframe-resizer/js/iframeResizer.min.js',
- to: 'bower_components/iframe-resizer/js'
- },
- {
- context: 'app/',
- from: 'bower_components/iframe-resizer/js/iframeResizer.contentWindow.min.js',
- to: 'bower_components/iframe-resizer/js'
- },
- {
- context: 'app/',
- from: 'bower_components/foundation/js/foundation.js',
- to: 'bower_components/foundation/js'
- },
- {
- context: 'app/',
- from: 'bower_components/foundation/js/foundation/foundation.reveal.js',
- to: 'bower_components/foundation/js/foundation'
- },
- {
- context: 'app/',
- from: 'bower_components/foundation/js/foundation/foundation.offcanvas.js',
- to: 'bower_components/foundation/js/foundation'
- },
- {
- context: 'app/',
- from: 'js/foundation/initialize_foundation.js',
- to: 'js/foundation'
- }
-])
diff --git a/web-ui/config/protected-assets-webpack.js b/web-ui/config/protected-assets-webpack.js
new file mode 100644
index 00000000..85654cf0
--- /dev/null
+++ b/web-ui/config/protected-assets-webpack.js
@@ -0,0 +1,25 @@
+var CopyWebpackPlugin = require('copy-webpack-plugin');
+
+module.exports = new CopyWebpackPlugin([
+ { context: 'app/', from: '404.html' },
+ { context: 'app/', from: 'index.html' },
+ { context: 'app/', from: 'sandbox.html' },
+ { context: 'app/', from: 'css/*' },
+ { context: 'src/backup_account/', from: 'backup_account.html' },
+ { context: 'app/bower_components/font-awesome/', from: 'fonts/*' },
+ { context: 'app/bower_components/font-awesome/', from: 'css/font-awesome.min.css', to: 'css' },
+ { context: 'app/bower_components/jquery-file-upload/', from: 'css/jquery.fileupload.css', to: 'css' },
+ { context: 'app/bower_components/modernizr/', from: 'modernizr.js' },
+ { context: 'app/bower_components/lodash/dist/', from: 'lodash.min.js' },
+ { context: 'app/bower_components/jquery/dist/', from: 'jquery.min.js' },
+ { context: 'app/bower_components/jquery-ui/', from: 'jquery-ui.min.js' },
+ { context: 'app/bower_components/jquery-file-upload/js/', from: 'jquery.fileupload.js' },
+ { context: 'app/bower_components/handlebars/', from: 'handlebars.min.js' },
+ { context: 'app/bower_components/typeahead.js/dist/', from: 'typeahead.bundle.min.js' },
+ { context: 'app/bower_components/iframe-resizer/js/', from: 'iframeResizer.min.js' },
+ { context: 'app/bower_components/iframe-resizer/js/', from: 'iframeResizer.contentWindow.min.js' },
+ { context: 'app/bower_components/foundation/js/', from: 'foundation.js' },
+ { context: 'app/bower_components/foundation/js/foundation/', from: 'foundation.reveal.js' },
+ { context: 'app/bower_components/foundation/js/foundation/', from: 'foundation.offcanvas.js' },
+ { context: 'app/js/foundation/', from: 'initialize_foundation.js' }
+])
diff --git a/web-ui/config/public-assets-webpack.js b/web-ui/config/public-assets-webpack.js
new file mode 100644
index 00000000..28dff566
--- /dev/null
+++ b/web-ui/config/public-assets-webpack.js
@@ -0,0 +1,10 @@
+var CopyWebpackPlugin = require('copy-webpack-plugin');
+
+module.exports = new CopyWebpackPlugin([
+ { context: 'src/login/', from: '*.html' },
+ { context: 'src/login/', from: '*.css' },
+ { context: 'src/interstitial/', from: '*' },
+ { context: 'app/', from: 'fonts/*' },
+ { context: 'app/', from: 'locales/**/*' },
+ { context: 'app/', from: 'images/**/*' }
+]);
diff --git a/web-ui/src/backup_account/backup_account.html b/web-ui/src/backup_account/backup_account.html
index fa026e7a..55881444 100644
--- a/web-ui/src/backup_account/backup_account.html
+++ b/web-ui/src/backup_account/backup_account.html
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
- <link rel="icon" type="image/png" href="assets/images/Favicon.png" />
+ <link rel="icon" type="image/png" href="public/images/Favicon.png" />
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
diff --git a/web-ui/src/backup_account/page.js b/web-ui/src/backup_account/page.js
index c39394e2..cc93a560 100644
--- a/web-ui/src/backup_account/page.js
+++ b/web-ui/src/backup_account/page.js
@@ -34,7 +34,7 @@ export const Page = ({ t }) => (
<div className='container'>
<img
className='backup-account-image'
- src='assets/images/forgot-my-password.svg'
+ src='/public/images/forgot-my-password.svg'
alt={t('backup-account.image-description')}
/>
<form>
diff --git a/web-ui/src/common/footer/footer.js b/web-ui/src/common/footer/footer.js
index 254a19f7..c2138c21 100644
--- a/web-ui/src/common/footer/footer.js
+++ b/web-ui/src/common/footer/footer.js
@@ -22,7 +22,7 @@ import './footer.scss';
export const Footer = ({ t }) => (
<footer className='footer-wrapper'>
<div className='footer-content'>
- <img className='footer-image' src='/assets/images/lab.svg' alt='' />
+ <img className='footer-image' src='/public/images/lab.svg' alt='' />
<div>
{t('footer-text')}
<a className='footer-link' href='mailto:team@pixelated-project.org'>
diff --git a/web-ui/src/common/header/header.js b/web-ui/src/common/header/header.js
index 9e5f6bc7..50c863b5 100644
--- a/web-ui/src/common/header/header.js
+++ b/web-ui/src/common/header/header.js
@@ -25,7 +25,7 @@ export const Header = ({ t }) => (
<a href='/'>
<img
className='header-logo'
- src='/startup-assets/pixelated-logo-orange.svg'
+ src='/public/images/logo-orange.svg'
alt='Pixelated'
/>
</a>
diff --git a/web-ui/src/i18n.js b/web-ui/src/i18n.js
index bbbe2dcd..64c7b8a1 100644
--- a/web-ui/src/i18n.js
+++ b/web-ui/src/i18n.js
@@ -32,7 +32,7 @@ i18n
.init({
fallbackLng: 'en_US',
backend: {
- loadPath: 'assets/locales/{{lng}}/{{ns}}.json'
+ loadPath: 'public/locales/{{lng}}/{{ns}}.json'
}
});
diff --git a/service/pixelated/assets/Interstitial.html b/web-ui/src/interstitial/interstitial.html
index bc6cc738..727883fe 100644
--- a/service/pixelated/assets/Interstitial.html
+++ b/web-ui/src/interstitial/interstitial.html
@@ -4,15 +4,15 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
- <script src="startup-assets/snap.svg-min.js"></script>
- <script src="startup-assets/jquery-2.1.3.min.js"></script>
+ <script src="/public/snap.svg-min.js"></script>
+ <script src="/public/jquery-2.1.3.min.js"></script>
</head>
<body style="border: 0px; padding: 0px; margin: 0px;background-color: #808181">
<section id="hive-section" style="background-color: #808181;" name="hive-section">
<svg id="hive" style="width: 100%; height: 100%;"></svg>
</section>
- <script src="startup-assets/Interstitial.js"></script>
+ <script src="/public/interstitial.js"></script>
</body>
</html>
diff --git a/service/pixelated/assets/Interstitial.js b/web-ui/src/interstitial/interstitial.js
index 2eaa7a1c..78a17190 100644
--- a/service/pixelated/assets/Interstitial.js
+++ b/web-ui/src/interstitial/interstitial.js
@@ -42,7 +42,7 @@ $(function () {
var handler = setInterval(function () {
$.ajax({
method: 'GET',
- url: '/login/status'
+ url: '/status'
}).success(function (data) {
if (data.status === 'completed' || data.status === 'error') {
window.location="/";
diff --git a/service/pixelated/assets/jquery-2.1.3.min.js b/web-ui/src/interstitial/jquery-2.1.3.min.js
index 25714ed2..25714ed2 100644
--- a/service/pixelated/assets/jquery-2.1.3.min.js
+++ b/web-ui/src/interstitial/jquery-2.1.3.min.js
diff --git a/service/pixelated/assets/snap.svg-min.js b/web-ui/src/interstitial/snap.svg-min.js
index ca9601ab..ca9601ab 100644
--- a/service/pixelated/assets/snap.svg-min.js
+++ b/web-ui/src/interstitial/snap.svg-min.js
diff --git a/service/pixelated/assets/_login_disclaimer_banner.html b/web-ui/src/login/_login_disclaimer_banner.html
index dfc63030..dfc63030 100644
--- a/service/pixelated/assets/_login_disclaimer_banner.html
+++ b/web-ui/src/login/_login_disclaimer_banner.html
diff --git a/web-ui/src/login/app.js b/web-ui/src/login/app.js
new file mode 100644
index 00000000..e6ac3192
--- /dev/null
+++ b/web-ui/src/login/app.js
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import React from 'react';
+import { translate } from 'react-i18next';
+
+const App = () => (
+ <form className='standard' id='login_form' action='/login' method='post'>
+ <input
+ type='text' name='username' id='email' className='text-field'
+ placeholder='username' autoFocus=''
+ />
+ <input
+ type='password' name='password' id='password' className='text-field'
+ placeholder='password' autoComplete='off'
+ />
+ <input type='submit' name='login' value='Login' className='button' />
+ </form>
+);
+
+export default translate('', { wait: true })(App);
diff --git a/service/pixelated/assets/pixelated.css b/web-ui/src/login/login.css
index b3e1d16e..51ab2046 100644
--- a/service/pixelated/assets/pixelated.css
+++ b/web-ui/src/login/login.css
@@ -1,10 +1,27 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
body {
font-family: "Open Sans", "Microsoft YaHei", "Hiragino Sans GB", "Hiragino Sans GB W3", "微软雅黑", "Helvetica Neue", Arial, sans-serif;
background-color: #EAEAEA;
height: 100vh;
color: #3E3A37;
- background-image: url("hive-bg.png");
+ background-image: url("/public/images/hive-bg.png");
background-repeat: repeat;
}
diff --git a/web-ui/src/login/login.html b/web-ui/src/login/login.html
new file mode 100644
index 00000000..b8c45180
--- /dev/null
+++ b/web-ui/src/login/login.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html xmlns:t="http://twistedmatrix.com/ns/twisted.web.template/0.1">
+ <head>
+ <link rel="icon" type="image/png" href="/public/images/Favicon.png" />
+ <meta charset="utf-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+ <meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
+ <title>Pixelated - Login</title>
+ <link rel="stylesheet" type="text/css" href="/public/normalize.min.css" />
+ <link rel="stylesheet" type="text/css" href="/public/login.css" />
+ <link rel="stylesheet" type="text/css" href="/public/opensans.css" />
+ </head>
+ <body>
+ <div class="content">
+ <div class="login">
+ <img class="logo" src="/public/images/logo-orange.svg" alt="Pixelated logo"/>
+ <p t:render="error_msg" class="error"></p>
+ <div id="root"/>
+ </div>
+ <div class="disclaimer">
+ <div t:render="disclaimer"></div>
+ </div>
+ </div>
+ <script type="text/javascript" src="/public/login.js"></script>
+ </body>
+</html>
diff --git a/web-ui/src/login/login.js b/web-ui/src/login/login.js
new file mode 100644
index 00000000..ddbe1943
--- /dev/null
+++ b/web-ui/src/login/login.js
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017 ThoughtWorks, Inc.
+ *
+ * Pixelated is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pixelated is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pixelated. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import React from 'react';
+import { render } from 'react-dom';
+import a11y from 'react-a11y';
+import { I18nextProvider } from 'react-i18next';
+
+import App from './app';
+import i18n from '../i18n';
+
+if (process.env.NODE_ENV === 'development') a11y(React);
+
+render(
+ <I18nextProvider i18n={i18n}>
+ <App />
+ </I18nextProvider>,
+ document.getElementById('root')
+);
diff --git a/service/pixelated/assets/normalize.min.css b/web-ui/src/login/normalize.min.css
index d3c7f4d5..d3c7f4d5 100644
--- a/service/pixelated/assets/normalize.min.css
+++ b/web-ui/src/login/normalize.min.css
diff --git a/service/pixelated/assets/opensans.css b/web-ui/src/login/opensans.css
index a42f346c..a42f346c 100644
--- a/service/pixelated/assets/opensans.css
+++ b/web-ui/src/login/opensans.css
diff --git a/web-ui/webpack.config.js b/web-ui/webpack.config.js
index 52188879..6a44e4a1 100644
--- a/web-ui/webpack.config.js
+++ b/web-ui/webpack.config.js
@@ -1,21 +1,12 @@
var path = require('path');
var webpack = require('webpack');
-var copyWebpack = require('./config/copy-webpack');
+var publicAssetsWebpack = require('./config/public-assets-webpack');
+var protectedAssetsWebpack = require('./config/protected-assets-webpack');
var loaders = require('./config/loaders-webpack');
var aliases = require('./config/alias-webpack');
-module.exports = {
- entry: {
- app: './app/js/index.js',
- backup_account: './src/backup_account/backup_account.js',
- sandbox: './app/js/sandbox.js'
- },
+var commonConfiguration = {
node: { fs: 'empty' },
- output: {
- path: path.join(__dirname, 'dist'),
- filename: '[name].js',
- publicPath: '/assets/'
- },
devtool: 'source-map',
resolve: {
alias: aliases,
@@ -24,10 +15,45 @@ module.exports = {
module: {
loaders: loaders
},
- plugins: [copyWebpack, new webpack.DefinePlugin({
- 'process.env': {
- NODE_ENV: JSON.stringify('development')
- }
- })],
postcss: {}
-}
+};
+
+var publicAssets = Object.assign({}, commonConfiguration, {
+ entry: {
+ 'login': './src/login/login.js',
+ },
+ output: {
+ path: path.join(__dirname, 'dist/public'),
+ filename: '[name].js',
+ publicPath: '/assets/'
+ },
+ plugins: [
+ publicAssetsWebpack,
+ new webpack.DefinePlugin({
+ 'process.env': {
+ NODE_ENV: JSON.stringify('development')
+ }
+ })]
+});
+
+var protectedAssets = Object.assign({}, commonConfiguration, {
+ entry: {
+ 'app': './app/js/index.js',
+ 'backup_account': './src/backup_account/backup_account.js',
+ 'sandbox': './app/js/sandbox.js'
+ },
+ output: {
+ path: path.join(__dirname, 'dist/protected'),
+ filename: '[name].js',
+ publicPath: '/assets/'
+ },
+ plugins: [
+ protectedAssetsWebpack,
+ new webpack.DefinePlugin({
+ 'process.env': {
+ NODE_ENV: JSON.stringify('development')
+ }
+ })]
+});
+
+module.exports = [publicAssets, protectedAssets];
diff --git a/web-ui/webpack.production.config.js b/web-ui/webpack.production.config.js
index 6ee08cac..92a4f12b 100644
--- a/web-ui/webpack.production.config.js
+++ b/web-ui/webpack.production.config.js
@@ -1,21 +1,13 @@
var path = require('path');
var webpack = require('webpack');
-var copyWebpack = require('./config/copy-webpack');
+var publicAssetsWebpack = require('./config/public-assets-webpack');
+var protectedAssetsWebpack = require('./config/protected-assets-webpack');
var loaders = require('./config/loaders-webpack');
var aliases = require('./config/alias-webpack');
-module.exports = {
- entry: {
- app: './app/js/index.js',
- backup_account: './src/backup_account/backup_account.js',
- sandbox: './app/js/sandbox.js'
- },
+var commonConfiguration = {
node: { fs: 'empty' },
- output: {
- path: path.join(__dirname, 'dist'),
- filename: '[name].js',
- publicPath: '/assets/'
- },
+ devtool: 'source-map',
resolve: {
alias: aliases,
extensions: ['', '.js']
@@ -23,14 +15,43 @@ module.exports = {
module: {
loaders: loaders
},
- plugins: [
- new webpack.optimize.UglifyJsPlugin(),
- new webpack.optimize.DedupePlugin(),
- new webpack.DefinePlugin({
- 'process.env': {
- NODE_ENV: JSON.stringify('production')
- }
- }),
- copyWebpack
- ]
-}
+ postcss: {}
+};
+
+var commonPlugins = [
+ new webpack.optimize.UglifyJsPlugin(),
+ new webpack.optimize.DedupePlugin(),
+ new webpack.DefinePlugin({
+ 'process.env': {
+ NODE_ENV: JSON.stringify('production')
+ }
+ })
+];
+
+var publicAssets = Object.assign({}, commonConfiguration, {
+ entry: {
+ 'login': './src/login/login.js',
+ },
+ output: {
+ path: path.join(__dirname, 'dist/public'),
+ filename: '[name].js',
+ publicPath: '/assets/'
+ },
+ plugins: commonPlugins.concat([ publicAssetsWebpack ])
+});
+
+var protectedAssets = Object.assign({}, commonConfiguration, {
+ entry: {
+ 'app': './app/js/index.js',
+ 'backup_account': './src/backup_account/backup_account.js',
+ 'sandbox': './app/js/sandbox.js'
+ },
+ output: {
+ path: path.join(__dirname, 'dist/protected'),
+ filename: '[name].js',
+ publicPath: '/assets/'
+ },
+ plugins: commonPlugins.concat([ protectedAssetsWebpack ])
+});
+
+module.exports = [publicAssets, protectedAssets];
diff --git a/web-ui/webpack.test.config.js b/web-ui/webpack.test.config.js
index 395c3949..e24e4540 100644
--- a/web-ui/webpack.test.config.js
+++ b/web-ui/webpack.test.config.js
@@ -1,6 +1,5 @@
var path = require('path');
var webpack = require('webpack');
-var copyWebpack = require('./config/copy-webpack');
var aliases = require('./config/alias-webpack');
module.exports = {