partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

commit 09eb8bdf76e98522324657f95700a0ce9760c3f7
parent b97e1e5ae8c9216bd1c133f225ad6a76b5563612
Author: Felicitus <felicitus@felicitus.org>
Date:   Wed, 23 Sep 2015 16:19:10 +0200

Implemented user preferences

Diffstat:
Mapp/config/config.yml | 44++++++++++++++++++++++++++++++++++++++++++++
Asrc/PartKeepr/AuthBundle/Action/GetPreferencesAction.php | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/PartKeepr/AuthBundle/Action/SetPreferenceAction.php | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/AuthBundle/DependencyInjection/PartKeeprAuthExtension.php | 3++-
Msrc/PartKeepr/AuthBundle/Entity/UserPreference.php | 20++++++++++++++------
Asrc/PartKeepr/AuthBundle/Resources/config/actions.xml | 19+++++++++++++++++++
Msrc/PartKeepr/AuthBundle/Services/UserPreferenceService.php | 9++++++---
Msrc/PartKeepr/AuthBundle/Tests/Services/UserPreferenceServiceTest.php | 9++++-----
Asrc/PartKeepr/AuthBundle/Tests/UserPreferenceTest.php | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/UserPreferenceGrid.js | 116++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Asrc/PartKeepr/FrontendBundle/Resources/public/js/Data/store/UserPreferenceStore.js | 20++++++++++++++++++++
Msrc/PartKeepr/FrontendBundle/Resources/public/js/PartKeepr.js | 882++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Msrc/PartKeepr/FrontendBundle/Resources/views/index.html.twig | 1+
13 files changed, 871 insertions(+), 480 deletions(-)

diff --git a/app/config/config.yml b/app/config/config.yml @@ -944,6 +944,46 @@ services: arguments: - { groups: [ "default" ] } + resource.user.item_operation.get_preferences: + class: "Dunglas\ApiBundle\Api\Operation\Operation" + public: false + factory: [ "@api.operation_factory", "createCollectionOperation" ] + arguments: + - "@resource.user" # Resource + - [ "GET" ] # Methods + - "/user_preferences" # Path + - "partkeepr.user_preference.get_preferences" # Controller + - "PartKeeprUserPreferenceGet" + + resource.user.item_operation.set_preference: + class: "Dunglas\ApiBundle\Api\Operation\Operation" + public: false + factory: [ "@api.operation_factory", "createCollectionOperation" ] + arguments: + - "@resource.user" # Resource + - [ "POST", "PUT" ] # Methods + - "/user_preferences" # Path + - "partkeepr.user_preference.set_preference" # Controller + - "PartKeeprUserPreferenceSet" + + resource.user.item_operation.get: + class: "Dunglas\ApiBundle\Api\Operation\Operation" + public: false + factory: [ "@api.operation_factory", "createItemOperation" ] + arguments: [ "@resource.user", "GET" ] + + resource.user.item_operation.put: + class: "Dunglas\ApiBundle\Api\Operation\Operation" + public: false + factory: [ "@api.operation_factory", "createItemOperation" ] + arguments: [ "@resource.user", "PUT" ] + + resource.user.item_operation.delete: + class: "Dunglas\ApiBundle\Api\Operation\Operation" + public: false + factory: [ "@api.operation_factory", "createItemOperation" ] + arguments: [ "@resource.user", "DELETE" ] + resource.user: parent: "api.resource" arguments: [ "PartKeepr\AuthBundle\Entity\User" ] @@ -953,6 +993,10 @@ services: arguments: [ [ "@doctrine_reflection_service.search_filter" ] ] - method: "initNormalizationContext" arguments: [ { groups: [ "default" ] } ] + - method: "initItemOperations" + arguments: [ [ "@resource.user.item_operation.get", "@resource.user.item_operation.get", "@resource.tempfile.item_operation.put", "@resource.user.item_operation.delete", "@resource.user.item_operation.get_preferences", "@resource.user.item_operation.set_preference" ] ] - method: "initDenormalizationContext" arguments: - { groups: [ "default" ] } + + diff --git a/src/PartKeepr/AuthBundle/Action/GetPreferencesAction.php b/src/PartKeepr/AuthBundle/Action/GetPreferencesAction.php @@ -0,0 +1,75 @@ +<?php +namespace PartKeepr\AuthBundle\Action; + +use Dunglas\ApiBundle\Action\ActionUtilTrait; +use Dunglas\ApiBundle\Api\ResourceInterface; +use Dunglas\ApiBundle\Exception\RuntimeException; +use PartKeepr\AuthBundle\Services\UserPreferenceService; +use PartKeepr\AuthBundle\Services\UserService; +use PartKeepr\CategoryBundle\Exception\RootNodeNotFoundException; +use Symfony\Bridge\Doctrine\ManagerRegistry; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Serializer\Serializer; + +/** + * Returns the tree root node + */ +class GetPreferencesAction +{ + use ActionUtilTrait; + + /** + * @var UserService + */ + private $userService; + + /** + * @var UserPreferenceService + */ + private $userPreferenceService; + + /** + * @var Serializer + */ + private $serializer; + + public function __construct( + UserService $userService, + UserPreferenceService $userPreferenceService, + Serializer $serializer + ) { + $this->userService = $userService; + $this->userPreferenceService = $userPreferenceService; + $this->serializer = $serializer; + } + + /** + * Retrieves a collection of resources. + * + * @param Request $request + * + * @return array|\Dunglas\ApiBundle\Model\PaginatorInterface|\Traversable + * + * @throws RuntimeException|RootNodeNotFoundException + */ + public function __invoke(Request $request) + { + $user = $this->userService->getUser(); + + $preferences = $this->userPreferenceService->getPreferences($user); + + list($resourceType) = $this->extractAttributes($request); + + /** + * @var ResourceInterface $resourceType + */ + $serializedData = $this->serializer->normalize( + $preferences, + 'json', + $resourceType->getNormalizationContext() + ); + + return new JsonResponse($serializedData); + } +} diff --git a/src/PartKeepr/AuthBundle/Action/SetPreferenceAction.php b/src/PartKeepr/AuthBundle/Action/SetPreferenceAction.php @@ -0,0 +1,84 @@ +<?php +namespace PartKeepr\AuthBundle\Action; + +use Dunglas\ApiBundle\Action\ActionUtilTrait; +use Dunglas\ApiBundle\Api\ResourceInterface; +use Dunglas\ApiBundle\Exception\RuntimeException; +use PartKeepr\AuthBundle\Services\UserPreferenceService; +use PartKeepr\AuthBundle\Services\UserService; +use PartKeepr\CategoryBundle\Exception\RootNodeNotFoundException; +use Symfony\Bridge\Doctrine\ManagerRegistry; +use Symfony\Component\HttpFoundation\JsonResponse; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Serializer\Serializer; + +/** + * Returns the tree root node + */ +class SetPreferenceAction +{ + use ActionUtilTrait; + + /** + * @var UserService + */ + private $userService; + + /** + * @var UserPreferenceService + */ + private $userPreferenceService; + + /** + * @var Serializer + */ + private $serializer; + + public function __construct( + UserService $userService, + UserPreferenceService $userPreferenceService, + Serializer $serializer + ) { + $this->userService = $userService; + $this->userPreferenceService = $userPreferenceService; + $this->serializer = $serializer; + } + + /** + * Retrieves a collection of resources. + * + * @param Request $request + * + * @return array|\Dunglas\ApiBundle\Model\PaginatorInterface|\Traversable + * @throws \Exception If the format is invalid + * + * @throws RuntimeException|RootNodeNotFoundException + */ + public function __invoke(Request $request) + { + $user = $this->userService->getUser(); + + $data = json_decode($request->getContent()); + + if ($data->preferenceKey && $data->preferenceValue) { + $preference = $this->userPreferenceService->setPreference($user, $data->preferenceKey, + $data->preferenceValue); + } else { + throw new \Exception("Invalid format"); + } + + list($resourceType) = $this->extractAttributes($request); + + /** + * @var ResourceInterface $resourceType + */ + + $serializedData = $this->serializer->normalize( + $preference, + 'json', + $resourceType->getNormalizationContext() + ); + + return new JsonResponse($serializedData); + } +} diff --git a/src/PartKeepr/AuthBundle/DependencyInjection/PartKeeprAuthExtension.php b/src/PartKeepr/AuthBundle/DependencyInjection/PartKeeprAuthExtension.php @@ -20,9 +20,10 @@ class PartKeeprAuthExtension extends Extension public function load(array $configs, ContainerBuilder $container) { $configuration = new Configuration(); - $config = $this->processConfiguration($configuration, $configs); + $this->processConfiguration($configuration, $configs); $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); $loader->load('services.xml'); + $loader->load('actions.xml'); } } diff --git a/src/PartKeepr/AuthBundle/Entity/UserPreference.php b/src/PartKeepr/AuthBundle/Entity/UserPreference.php @@ -3,6 +3,8 @@ namespace PartKeepr\AuthBundle\Entity; use Doctrine\ORM\Mapping as ORM; use PartKeepr\AuthBundle\Entity\User; +use PartKeepr\DoctrineReflectionBundle\Annotation\TargetService; +use Symfony\Component\Serializer\Annotation\Groups; /** * Represents a user preference entry. @@ -13,14 +15,17 @@ use PartKeepr\AuthBundle\Entity\User; * Note that values are stored internally as serialized PHP values to keep their type. * * @ORM\Entity + * @TargetService(uri="/api/user_preferences") **/ class UserPreference { /** * Defines the key of the user preference * @ORM\Column(type="string",length=255) + * @ORM\Id() + * + * @Groups({"default"}) * - * @ORM\Id * @var string */ private $preferenceKey; @@ -29,6 +34,9 @@ class UserPreference * Defines the value. Note that the value is internally stored as a serialized string. * * @ORM\Column(type="text") + * + * @Groups({"default"}) + * * @var mixed */ private $preferenceValue; @@ -36,8 +44,8 @@ class UserPreference /** * Defines the user * @ORM\ManyToOne(targetEntity="PartKeepr\AuthBundle\Entity\User") + * @ORM\Id() * - * @ORM\Id * @var \PartKeepr\AuthBundle\Entity\User */ private $user; @@ -68,7 +76,7 @@ class UserPreference * * @param string $key The key name */ - public function setKey($key) + public function setPreferenceKey($key) { $this->preferenceKey = $key; } @@ -78,7 +86,7 @@ class UserPreference * * @return string */ - public function getKey() + public function getPreferenceKey() { return $this->preferenceKey; } @@ -88,7 +96,7 @@ class UserPreference * * @param mixed $value */ - public function setValue($value) + public function setPreferenceValue($value) { $this->preferenceValue = serialize($value); } @@ -98,7 +106,7 @@ class UserPreference * * @return mixed The value */ - public function getValue() + public function getPreferenceValue() { return unserialize($this->preferenceValue); } diff --git a/src/PartKeepr/AuthBundle/Resources/config/actions.xml b/src/PartKeepr/AuthBundle/Resources/config/actions.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" ?> + +<container xmlns="http://symfony.com/schema/dic/services" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> + + <services> + <service id="partkeepr.user_preference.get_preferences" class="PartKeepr\AuthBundle\Action\GetPreferencesAction"> + <argument type="service" id="partkeepr.userservice"/> + <argument type="service" id="partkeepr.user_preference_service"/> + <argument type="service" id="api.serializer"/> + </service> + <service id="partkeepr.user_preference.set_preference" class="PartKeepr\AuthBundle\Action\SetPreferenceAction"> + <argument type="service" id="partkeepr.userservice"/> + <argument type="service" id="partkeepr.user_preference_service"/> + <argument type="service" id="api.serializer"/> + </service> + </services> +</container> diff --git a/src/PartKeepr/AuthBundle/Services/UserPreferenceService.php b/src/PartKeepr/AuthBundle/Services/UserPreferenceService.php @@ -27,6 +27,8 @@ class UserPreferenceService * @param string $key The key to set * @param string $value The value to set * + * @return UserPreference The user preference + * * @throws EntityNotPersistantException Thrown if the entity is not persistant */ public function setPreference(User $user, $key, $value) @@ -47,12 +49,12 @@ class UserPreferenceService } catch (\Exception $e) { $userPreference = new UserPreference(); $userPreference->setUser($user); - $userPreference->setKey($key); + $userPreference->setPreferenceKey($key); $this->entityManager->persist($userPreference); } - $userPreference->setValue($value); + $userPreference->setPreferenceValue($value); $this->entityManager->flush(); @@ -73,7 +75,7 @@ class UserPreferenceService { $userPreference = $this->getPreference($user, $key); - return $userPreference->getValue(); + return $userPreference->getPreferenceValue(); } /** @@ -81,6 +83,7 @@ class UserPreferenceService * * @param \PartKeepr\AuthBundle\Entity\User $user The user * + * @return UserPreference[] An array of UserPreference objects * @throws EntityNotPersistantException Thrown if the user entity is not persistent */ public function getPreferences(User $user) diff --git a/src/PartKeepr/AuthBundle/Tests/Services/UserPreferenceServiceTest.php b/src/PartKeepr/AuthBundle/Tests/Services/UserPreferenceServiceTest.php @@ -1,7 +1,6 @@ <?php namespace PartKeepr\AuthBundle\Tests\Services; -use Doctrine\Common\DataFixtures\ProxyReferenceRepository; use Liip\FunctionalTestBundle\Test\WebTestCase; use PartKeepr\AuthBundle\Entity\User; @@ -26,16 +25,16 @@ class UserPreferenceServiceTest extends WebTestCase $this->assertArrayHasKey(0, $preferences); $this->assertEquals(get_class($preferences[0]), "PartKeepr\AuthBundle\Entity\UserPreference"); - $this->assertEquals("bar", $preferences[0]->getValue()); - $this->assertEquals("foo", $preferences[0]->getKey()); + $this->assertEquals("bar", $preferences[0]->getPreferenceValue()); + $this->assertEquals("foo", $preferences[0]->getPreferenceKey()); $this->assertEquals($user, $preferences[0]->getUser()); $preference = $service->getPreference($user, "foo"); $this->assertEquals(get_class($preference), "PartKeepr\AuthBundle\Entity\UserPreference"); - $this->assertEquals("bar", $preference->getValue()); - $this->assertEquals("foo", $preference->getKey()); + $this->assertEquals("bar", $preference->getPreferenceValue()); + $this->assertEquals("foo", $preference->getPreferenceKey()); $this->assertEquals($user, $preference->getUser()); $service->deletePreference($user, "foo"); diff --git a/src/PartKeepr/AuthBundle/Tests/UserPreferenceTest.php b/src/PartKeepr/AuthBundle/Tests/UserPreferenceTest.php @@ -0,0 +1,69 @@ +<?php +namespace PartKeepr\AuthBundle\Tests; + + +use Doctrine\Common\DataFixtures\ProxyReferenceRepository; +use Liip\FunctionalTestBundle\Test\WebTestCase; + +class UserPreferenceTest extends WebTestCase +{ + /** + * @var ProxyReferenceRepository + */ + private $fixtures; + + public function setUp() + { + $this->fixtures = $this->loadFixtures( + array( + 'PartKeepr\AuthBundle\DataFixtures\LoadUserData', + ) + )->getReferenceRepository(); + } + + public function testPreferences() + { + $client = static::makeClient(true); + + $request = array( + "preferenceKey" => "foobar", + "preferenceValue" => "1234", + ); + + $client->request( + 'POST', + '/api/user_preferences', + array(), + array(), + array('CONTENT_TYPE' => 'application/json'), + json_encode($request) + ); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertObjectHasAttribute("preferenceKey", $response); + $this->assertObjectHasAttribute("preferenceValue", $response); + $this->assertEquals("foobar", $response->preferenceKey); + $this->assertEquals("1234", $response->preferenceValue); + + $client->request( + 'GET', + '/api/user_preferences', + array(), + array(), + array('CONTENT_TYPE' => 'application/json') + ); + + $response = json_decode($client->getResponse()->getContent()); + + $this->assertInternalType("array", $response); + + $preference = $response[0]; + + $this->assertObjectHasAttribute("preferenceKey", $preference); + $this->assertObjectHasAttribute("preferenceValue", $preference); + $this->assertEquals("foobar", $preference->preferenceKey); + $this->assertEquals("1234", $preference->preferenceValue); + + } +} diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/UserPreferenceGrid.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Components/Widgets/UserPreferenceGrid.js @@ -1,25 +1,28 @@ Ext.define('PartKeepr.UserPreferenceGrid', { - extend: 'PartKeepr.BaseGrid', + extend: 'PartKeepr.BaseGrid', - columnLines: true, - - columns: [{ - header: i18n("Key"), - dataIndex: 'key', - flex: 0.3, - minWidth: 200, - renderer: Ext.util.Format.htmlEncode - },{ - header: i18n("Value"), - dataIndex: 'value', - flex: 0.7, - minWidth: 200, - renderer: Ext.util.Format.htmlEncode - }], + columnLines: true, + + columns: [ + { + header: i18n("Key"), + dataIndex: 'key', + flex: 0.3, + minWidth: 200, + renderer: Ext.util.Format.htmlEncode + }, { + header: i18n("Value"), + dataIndex: 'value', + flex: 0.7, + minWidth: 200, + renderer: Ext.util.Format.htmlEncode + } + ], userId: null, - - initComponent: function () { - this.deleteButton = Ext.create("Ext.button.Button", { + + initComponent: function () + { + this.deleteButton = Ext.create("Ext.button.Button", { text: i18n('Delete'), disabled: true, itemId: 'delete', @@ -27,45 +30,50 @@ Ext.define('PartKeepr.UserPreferenceGrid', { icon: 'resources/silkicons/delete.png', handler: this.onDeleteClick }); - - this.dockedItems = [{ - xtype: 'toolbar', - items: [ - this.deleteButton - ] - }]; - this.store = Ext.create("Ext.data.Store", { - model: 'PartKeepr.UserPreference', - pageSize: 999999999 - }); - - this.callParent(); - - this.getSelectionModel().on('selectionchange', this.onSelectChange, this); - }, - onDeleteClick: function () { - var selection = this.getView().getSelectionModel().getSelection()[0]; + + this.dockedItems = [ + { + xtype: 'toolbar', + items: [ + this.deleteButton + ] + } + ]; + this.store = Ext.create("Ext.data.Store", { + model: 'PartKeepr.AuthBundle.Entity.UserPreference', + pageSize: 999999999 + }); + + this.callParent(); + + this.getSelectionModel().on('selectionchange', this.onSelectChange, this); + }, + onDeleteClick: function () + { + var selection = this.getView().getSelectionModel().getSelection()[0]; if (selection) { - // Set phantom to false because ExtJS has problems with PK-less thingies - selection.phantom = false; + // Set phantom to false because ExtJS has problems with PK-less thingies + selection.phantom = false; this.store.remove(selection); } - }, - onSelectChange: function(selModel, selections){ + }, + onSelectChange: function (selModel, selections) + { this.deleteButton.setDisabled(selections.length === 0); }, - syncPreferences: function () { - /* Iterate through all removed records and issue an AJAX - * call. This is necessary because the server side doesn't suport string - * keys and ExtJS can't handle composite keys. - */ - for (var j=0;j<this.store.removed.length;j++) { - var call = new PartKeepr.ServiceCall("UserPreference", "destroy"); - call.setParameter("key", this.store.removed[j].get("key")); - call.setParameter("user_id", this.store.removed[j].get("user_id")); - call.doCall(); - } - - this.store.removed = []; + syncPreferences: function () + { + /* Iterate through all removed records and issue an AJAX + * call. This is necessary because the server side doesn't suport string + * keys and ExtJS can't handle composite keys. + */ + for (var j = 0; j < this.store.removed.length; j++) { + var call = new PartKeepr.ServiceCall("UserPreference", "destroy"); + call.setParameter("key", this.store.removed[j].get("key")); + call.setParameter("user_id", this.store.removed[j].get("user_id")); + call.doCall(); + } + + this.store.removed = []; } }); diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/Data/store/UserPreferenceStore.js b/src/PartKeepr/FrontendBundle/Resources/public/js/Data/store/UserPreferenceStore.js @@ -0,0 +1,20 @@ +Ext.define('PartKeepr.data.store.UserPreferenceStore', { + extend: 'Ext.data.Store', + + /** + * The store ID to use + */ + storeId: 'UserPreferenceStore', + + /** + * Automatically load the store + */ + autoLoad: true, + + /** + * The model to use + */ + model: "PartKeepr.AuthBundle.Entity.UserPreference", + + pageSize: 99999999 +}); diff --git a/src/PartKeepr/FrontendBundle/Resources/public/js/PartKeepr.js b/src/PartKeepr/FrontendBundle/Resources/public/js/PartKeepr.js @@ -1,89 +1,93 @@ -Ext.namespace('PartKeepr'); - +Ext.namespace('PartKeepr'); + PartKeepr.application = null; Ext.application({ name: 'PartKeepr', - launch: function() { + launch: function () + { Ext.setGlyphFontFamily('FontAwesome'); - Ext.get("loading").hide(); - Ext.setLocale('en_US'); - - this.createLayout(); - - PartKeepr.application = this; - - // Set static data of the server - PartKeepr.setMaxUploadSize(window.parameters.maxUploadSize); - PartKeepr.setAvailableImageFormats(window.parameters.availableImageFormats); - - this.sessionManager = new PartKeepr.SessionManager(); - - /* Automatic session starting is active. This disables login/logout functionality. */ - if (window.parameters.auto_start_session) { - this.getSessionManager().setSession(window.parameters.auto_start_session); - this.getStatusbar().connectionButton.hide(); + Ext.get("loading").hide(); + Ext.setLocale('en_US'); + + this.createLayout(); + + PartKeepr.application = this; + + // Set static data of the server + PartKeepr.setMaxUploadSize(window.parameters.maxUploadSize); + PartKeepr.setAvailableImageFormats(window.parameters.availableImageFormats); + + this.sessionManager = new PartKeepr.SessionManager(); + + /* Automatic session starting is active. This disables login/logout functionality. */ + if (window.parameters.auto_start_session) { + this.getSessionManager().setSession(window.parameters.auto_start_session); + this.getStatusbar().connectionButton.hide(); this.setUsername(window.parameters.autoLoginUsername); - this.onLogin(); - } else { - // If auto login is wanted (for e.g. demo systems), put it in here - this.sessionManager.on("login", this.onLogin, this); - - if (window.parameters.autoLoginUsername) { - this.sessionManager.login(window.parameters.autoLoginUsername, window.parameters.autoLoginPassword); - } else { - this.sessionManager.login(); - } - } - + this.onLogin(); + } else { + // If auto login is wanted (for e.g. demo systems), put it in here + this.sessionManager.on("login", this.onLogin, this); + + if (window.parameters.autoLoginUsername) { + this.sessionManager.login(window.parameters.autoLoginUsername, window.parameters.autoLoginPassword); + } else { + this.sessionManager.login(); + } + } + Ext.fly(document.body).on('contextmenu', this.onContextMenu, this); }, - getPartManager: function () { + getPartManager: function () + { return this.partManager; }, - onContextMenu: function (e, target) { - if (!e.ctrlKey) { - e.preventDefault(); - } + onContextMenu: function (e, target) + { + if (!e.ctrlKey) { + e.preventDefault(); + } }, /** * Handles the login function. Initializes the part manager window, * enables the menu bar and creates the stores+loads them. */ - onLogin: function () { - this.createGlobalStores(); - - if (window.parameters.userPreferences) { - PartKeepr.getApplication().setInitialUserPreferences(window.parameters.userPreferences); - } - - if (PartKeepr.initialUserPreferences) { - var records = this.getUserPreferenceStore().getProxy().getReader().read(PartKeepr.initialUserPreferences); - this.getUserPreferenceStore().loadRecords(records.records); - } - - this.reloadStores(); + onLogin: function () + { + this.createGlobalStores(); + + if (window.parameters.userPreferences) { + PartKeepr.getApplication().setInitialUserPreferences(window.parameters.userPreferences); + } + + if (PartKeepr.initialUserPreferences) { + var records = this.getUserPreferenceStore().getProxy().getReader().read(PartKeepr.initialUserPreferences); + this.getUserPreferenceStore().loadRecords(records.records); + } + + this.reloadStores(); this.createPartManager(); - this.menuBar.enable(); - - this.doSystemStatusCheck(); - this.doUnacknowledgedNoticesCheck(); - - /* Give the user preference stuff enough time to load */ - /* @todo Load user preferences directly on login and not via delayed task */ - this.displayTipWindowTask = new Ext.util.DelayedTask(this.displayTipOfTheDayWindow, this); - this.displayTipWindowTask.delay(100); + this.menuBar.enable(); + + this.doSystemStatusCheck(); + this.doUnacknowledgedNoticesCheck(); + + /* Give the user preference stuff enough time to load */ + /* @todo Load user preferences directly on login and not via delayed task */ + this.displayTipWindowTask = new Ext.util.DelayedTask(this.displayTipOfTheDayWindow, this); + this.displayTipWindowTask.delay(100); if (window.parameters.motd) { this.displayMOTD(); } - this.setSession(this.getSessionManager().getSession()); - - this.getStatusbar().getConnectionButton().setConnected(); - + this.setSession(this.getSessionManager().getSession()); + + this.getStatusbar().getConnectionButton().setConnected(); + }, /** * Re-creates the part manager. This is usually called when the "compactLayout" configuration option has been @@ -92,7 +96,8 @@ Ext.application({ * @param none * @return nothing */ - recreatePartManager: function () { + recreatePartManager: function () + { this.centerPanel.remove(this.partManager); this.getPartManager().destroy(); @@ -102,7 +107,8 @@ Ext.application({ * Creates the part manager. While this is usually only done after login, it can also happen when the user changes * the "compact" preference. */ - createPartManager: function () { + createPartManager: function () + { this.partManager = Ext.create("PartKeepr.PartManager", { title: i18n("Part Manager"), compactLayout: PartKeepr.getApplication().getUserPreference("partkeepr.partmanager.compactlayout", false), @@ -115,66 +121,72 @@ Ext.application({ /** * Sets the initial user preferences, which are applied into the userPreferenceStore after login. */ - setInitialUserPreferences: function (obj) { - PartKeepr.initialUserPreferences = obj; + setInitialUserPreferences: function (obj) + { + PartKeepr.initialUserPreferences = obj; }, /** * Displays the tip of the day window. - * + * * This method checks if the user has disabled tips, and if so, this method - * avoids showing the window. + * avoids showing the window. */ - displayTipOfTheDayWindow: function () { - if (!this.tipOfTheDayStore._loaded) { - this.displayTipWindowTask.delay(100); - return; - } - - if (PartKeepr.getApplication().getUserPreference("partkeepr.tipoftheday.showtips") !== false) { - var j = Ext.create("PartKeepr.TipOfTheDayWindow"); - - if (j.getLastUnreadTip() !== null) { - j.show(); - } - } + displayTipOfTheDayWindow: function () + { + if (!this.tipOfTheDayStore._loaded) { + this.displayTipWindowTask.delay(100); + return; + } + + if (PartKeepr.getApplication().getUserPreference("partkeepr.tipoftheday.showtips") !== false) { + var j = Ext.create("PartKeepr.TipOfTheDayWindow"); + + if (j.getLastUnreadTip() !== null) { + j.show(); + } + } }, /** * Displays a message-of-the-day */ - displayMOTD: function () { + displayMOTD: function () + { Ext.MessageBox.alert(i18n("Message of the day"), window.parameters.motd); }, /** * Does a schema status call against the PartKeepr installation, in order to verify if the schema is up-to-date. - * + * * @param none * @return nothing */ - doSystemStatusCheck: function () { - var call = new PartKeepr.ServiceCall("api", "system_status"); - call.setHandler(Ext.bind(this.onSystemStatusCheck, this)); - call.doCall(); + doSystemStatusCheck: function () + { + var call = new PartKeepr.ServiceCall("api", "system_status"); + call.setHandler(Ext.bind(this.onSystemStatusCheck, this)); + call.doCall(); }, /** - * Handler for the schema check + * Handler for the schema check * @param data The data returned from the server */ - onSystemStatusCheck: function (data) { - if (data.schemaStatus !== "complete") { - alert(i18n("Your database schema is not up-to-date! Please re-run setup immediately!")); - } - - if (data.inactiveCronjobCount > 0) { - alert(i18n("The following cronjobs aren't running:")+"\n\n"+data.inactiveCronjobs.join("\n")); - } + onSystemStatusCheck: function (data) + { + if (data.schemaStatus !== "complete") { + alert(i18n("Your database schema is not up-to-date! Please re-run setup immediately!")); + } + + if (data.inactiveCronjobCount > 0) { + alert(i18n("The following cronjobs aren't running:") + "\n\n" + data.inactiveCronjobs.join("\n")); + } }, /** * Returns the session manager - * + * * @returns SessionManager */ - getSessionManager: function () { - return this.sessionManager; + getSessionManager: function () + { + return this.sessionManager; }, /* * Checks for unacknowledged system notices. Triggers a service call against the server. @@ -184,115 +196,117 @@ Ext.application({ * @param none * @return nothing */ - doUnacknowledgedNoticesCheck: function () { - if (this.getSessionManager().getSession() !== null) { - var call = new PartKeepr.ServiceCall("SystemNotice", "hasUnacknowledgedNotices"); - - call.setHandler(Ext.bind(this.onUnacknowledgedNoticesCheck, this)); - call.doCall(); - } - }, - /** - * Handler for the unacknowledged system notices check + doUnacknowledgedNoticesCheck: function () + { + if (this.getSessionManager().getSession() !== null) { + var call = new PartKeepr.ServiceCall("SystemNotice", "hasUnacknowledgedNotices"); + + call.setHandler(Ext.bind(this.onUnacknowledgedNoticesCheck, this)); + call.doCall(); + } + }, + /** + * Handler for the unacknowledged system notices check * @param data The data returned from the server */ - onUnacknowledgedNoticesCheck: function (data) { - if (data.data.unacknowledgedNotices === true) { - this.statusBar.systemNoticeButton.show(); - } else { - this.statusBar.systemNoticeButton.hide(); - } - - Ext.defer(this.doUnacknowledgedNoticesCheck, 10000, this); - }, - logout: function () { - this.menuBar.disable(); - this.centerPanel.removeAll(true); - this.getSessionManager().logout(); - }, - createGlobalStores: function () { - this.footprintStore = Ext.create("Ext.data.Store", - { - model: 'PartKeepr.FootprintBundle.Entity.Footprint', - pageSize: 99999999, - autoLoad: true - }); - - this.siPrefixStore = Ext.create("Ext.data.Store", - { - model: 'PartKeepr.SiPrefixBundle.Entity.SiPrefix', - pageSize: 99999999, - autoLoad: true - }); - - this.distributorStore = Ext.create("Ext.data.Store", - { - model: 'PartKeepr.DistributorBundle.Entity.Distributor', - pageSize: 99999999, - autoLoad: true - }); - - this.manufacturerStore = Ext.create("Ext.data.Store", - { - model: 'PartKeepr.ManufacturerBundle.Entity.Manufacturer', - pageSize: 99999999, - autoLoad: true - }); - - this.partUnitStore = Ext.create("Ext.data.Store", - { - model: 'PartKeepr.PartBundle.Entity.PartMeasurementUnit', - pageSize: 99999999, - autoLoad: true - }); - - this.unitStore = Ext.create("Ext.data.Store", - { - model: 'PartKeepr.UnitBundle.Entity.Unit', - pageSize: 99999999, - autoLoad: true - }); - - this.userStore = Ext.create("Ext.data.Store", - { - model: 'PartKeepr.AuthBundle.Entity.User', - pageSize: 99999999, - autoLoad: true - }); - - this.tipOfTheDayStore = Ext.create("Ext.data.Store", - { - model: 'PartKeepr.TipOfTheDayBundle.Entity.TipOfTheDay', - pageSize: 99999999, - autoLoad: true, - listeners: { - scope: this, - load: this.storeLoaded - } - }); - - this.userPreferenceStore = Ext.create("Ext.data.Store", - { - model: 'PartKeepr.AuthBundle.Entity.UserPreference', - pageSize: 99999999, - autoLoad: false, - listeners: { - scope: this, - load: this.storeLoaded - } - }); - }, - storeLoaded: function (store) { - store._loaded = true; - }, - setAdmin: function (admin) { - this.admin = admin; - }, - isAdmin: function () { - return this.admin; - }, - getTipOfTheDayStore: function () { - return this.tipOfTheDayStore; + onUnacknowledgedNoticesCheck: function (data) + { + if (data.data.unacknowledgedNotices === true) { + this.statusBar.systemNoticeButton.show(); + } else { + this.statusBar.systemNoticeButton.hide(); + } + + Ext.defer(this.doUnacknowledgedNoticesCheck, 10000, this); + }, + logout: function () + { + this.menuBar.disable(); + this.centerPanel.removeAll(true); + this.getSessionManager().logout(); + }, + createGlobalStores: function () + { + this.footprintStore = Ext.create("Ext.data.Store", + { + model: 'PartKeepr.FootprintBundle.Entity.Footprint', + pageSize: 99999999, + autoLoad: true + }); + + this.siPrefixStore = Ext.create("Ext.data.Store", + { + model: 'PartKeepr.SiPrefixBundle.Entity.SiPrefix', + pageSize: 99999999, + autoLoad: true + }); + + this.distributorStore = Ext.create("Ext.data.Store", + { + model: 'PartKeepr.DistributorBundle.Entity.Distributor', + pageSize: 99999999, + autoLoad: true + }); + + this.manufacturerStore = Ext.create("Ext.data.Store", + { + model: 'PartKeepr.ManufacturerBundle.Entity.Manufacturer', + pageSize: 99999999, + autoLoad: true + }); + + this.partUnitStore = Ext.create("Ext.data.Store", + { + model: 'PartKeepr.PartBundle.Entity.PartMeasurementUnit', + pageSize: 99999999, + autoLoad: true + }); + + this.unitStore = Ext.create("Ext.data.Store", + { + model: 'PartKeepr.UnitBundle.Entity.Unit', + pageSize: 99999999, + autoLoad: true + }); + + this.userStore = Ext.create("Ext.data.Store", + { + model: 'PartKeepr.AuthBundle.Entity.User', + pageSize: 99999999, + autoLoad: true + }); + + this.tipOfTheDayStore = Ext.create("Ext.data.Store", + { + model: 'PartKeepr.TipOfTheDayBundle.Entity.TipOfTheDay', + pageSize: 99999999, + autoLoad: true, + listeners: { + scope: this, + load: this.storeLoaded + } + }); + + this.userPreferenceStore = Ext.create("PartKeepr.data.store.UserPreferenceStore", + { + model: 'PartKeepr.AuthBundle.Entity.UserPreference', + }); + }, + storeLoaded: function (store) + { + store._loaded = true; + }, + setAdmin: function (admin) + { + this.admin = admin; + }, + isAdmin: function () + { + return this.admin; + }, + getTipOfTheDayStore: function () + { + return this.tipOfTheDayStore; }, /** * Queries for a specific user preference. Returns either the value or a default value if @@ -301,146 +315,164 @@ Ext.application({ * @param defaultValue A default value to return (optional) * @returns the key value, or defaultValue if preference key was not found */ - getUserPreference: function (key, defaultValue) { - var record = this.userPreferenceStore.findRecord("key", key); - - if (record) { - return record.get("value"); - } else { - return (typeof defaultValue == "undefined") ? null : defaultValue; - } + getUserPreference: function (key, defaultValue) + { + var record = this.userPreferenceStore.findRecord("preferenceKey", key); + + if (record) { + return record.get("preferenceValue"); + } else { + return (typeof defaultValue == "undefined") ? null : defaultValue; + } }, /** * Sets a specific user preference. Directly commits the change to the server. - * + * * @param key The key to set * @param value The value to set */ - setUserPreference: function (key, value) { - var record = this.userPreferenceStore.findRecord("key", key); - - if (record) { - record.set("value", value); - } else { - var j = new PartKeepr.UserPreference(); - j.set("key", key); - j.set("value", value); - - this.userPreferenceStore.add(j); - } - - this.userPreferenceStore.sync(); + setUserPreference: function (key, value) + { + var record = this.userPreferenceStore.findRecord("preferenceKey", key); + + if (record) { + record.set("preferenceValue", value); + } else { + var j = new PartKeepr.AuthBundle.Entity.UserPreference(); + j.set("preferenceKey", key); + j.set("preferenceValue", value); + + this.userPreferenceStore.add(j); + } + + this.userPreferenceStore.sync(); }, - getUserPreferenceStore: function () { - return this.userPreferenceStore; + getUserPreferenceStore: function () + { + return this.userPreferenceStore; }, - getUnitStore: function () { - return this.unitStore; + getUnitStore: function () + { + return this.unitStore; }, - getPartUnitStore: function () { - return this.partUnitStore; + getPartUnitStore: function () + { + return this.partUnitStore; }, - getFootprintStore: function () { - return this.footprintStore; + getFootprintStore: function () + { + return this.footprintStore; }, - getManufacturerStore: function () { - return this.manufacturerStore; + getManufacturerStore: function () + { + return this.manufacturerStore; }, - getDistributorStore: function () { - return this.distributorStore; + getDistributorStore: function () + { + return this.distributorStore; }, - getDefaultPartUnit: function () { - return this.partUnitStore.findRecord("default", true); + getDefaultPartUnit: function () + { + return this.partUnitStore.findRecord("default", true); }, - getUserStore: function () { - return this.userStore; + getUserStore: function () + { + return this.userStore; }, - getSiPrefixStore: function () { - return this.siPrefixStore; + getSiPrefixStore: function () + { + return this.siPrefixStore; }, /** * Converts the Character "micro" (µ, available on german keyboards via AltGr+m) to the Character "Mu" (μ). - * + * * The standard for Si-Prefixes defines that the "Mu"-character should be used instead of the "micro" character. - * + * * Wikipedia Entry for the "Micro" Si Prefix: http://en.wikipedia.org/wiki/Micro- - * + * */ - convertMicroToMu: function (value) { - /** - * Since the Si-Prefix for "micro" is μ, but keyboard have "µ" on it - * (note: both chars might look identical, depending on your font), we need - * to convert "µ" (on the keyboard, Unicode U+00B5) to the Mu (U+03BC). - */ - - return str_replace("µ", "μ", value); + convertMicroToMu: function (value) + { + /** + * Since the Si-Prefix for "micro" is μ, but keyboard have "µ" on it + * (note: both chars might look identical, depending on your font), we need + * to convert "µ" (on the keyboard, Unicode U+00B5) to the Mu (U+03BC). + */ + + return str_replace("µ", "μ", value); }, /** * Reload all global stores each 100 seconds. - * + * * @todo In the future, it would be nice to trigger a specific * store reload when something happens. Example: - * + * * If the user pulls down the storage location combo box, * reload it. - * + * * YES, this is becoming nasty. We have now 6 stores, each * reloading every minute. This NEEDS to be fixed soon! - * + * */ - reloadStores: function () { - if (this.getSessionManager().getSession()) { - this.footprintStore.load(); - this.manufacturerStore.load(); - this.distributorStore.load(); - this.partUnitStore.load(); - this.unitStore.load(); - this.userStore.load(); - Ext.defer(PartKeepr.getApplication().reloadStores, 100000, this); - } + reloadStores: function () + { + if (this.getSessionManager().getSession()) { + this.footprintStore.load(); + this.manufacturerStore.load(); + this.distributorStore.load(); + this.partUnitStore.load(); + this.unitStore.load(); + this.userStore.load(); + Ext.defer(PartKeepr.getApplication().reloadStores, 100000, this); + } }, /** * Creates the main view of PartKeepr. */ - createLayout: function () { - - this.statusBar = Ext.create("PartKeepr.Statusbar"); - - this.messageLog = this.createMessageLog(); - - this.centerPanel = Ext.create("Ext.tab.Panel", { - xtype: 'tabpanel', - border: false, - region: 'center', - bodyStyle: 'background:#DBDBDB', - plugins: Ext.create('Ext.ux.TabCloseMenu') - - }); - - this.menuBar = Ext.create("PartKeepr.MenuBar"); - - this.menuBar.disable(); - Ext.create('Ext.container.Viewport', { - layout: 'fit', - items: [{ - xtype: 'panel', - border: false, - layout: 'border', - items: [ - this.centerPanel, - this.messageLog - ], - bbar: this.statusBar, - tbar: this.menuBar - }] + createLayout: function () + { + + this.statusBar = Ext.create("PartKeepr.Statusbar"); + + this.messageLog = this.createMessageLog(); + + this.centerPanel = Ext.create("Ext.tab.Panel", { + xtype: 'tabpanel', + border: false, + region: 'center', + bodyStyle: 'background:#DBDBDB', + plugins: Ext.create('Ext.ux.TabCloseMenu') + + }); + + this.menuBar = Ext.create("PartKeepr.MenuBar"); + + this.menuBar.disable(); + Ext.create('Ext.container.Viewport', { + layout: 'fit', + items: [ + { + xtype: 'panel', + border: false, + layout: 'border', + items: [ + this.centerPanel, + this.messageLog + ], + bbar: this.statusBar, + tbar: this.menuBar + } + ] }); }, - addItem: function (item) { - this.centerPanel.add(item); + addItem: function (item) + { + this.centerPanel.add(item); }, - createMessageLog: function () { - return Ext.create("PartKeepr.MessageLog", { + createMessageLog: function () + { + return Ext.create("PartKeepr.MessageLog", { height: 200, hidden: true, split: true, @@ -449,147 +481,175 @@ Ext.application({ collapsible: true, region: 'south', listeners: { - beforecollapse: Ext.bind( - function (obj) { - this.hideMessageLog(); - return false; - }, - this) - } - }); - }, - log: function (message) { - this.logMessage(message, "none"); - }, - logMessage: function (message, severity) { - if (message != i18n("Ready.")) { - var r = Ext.ModelManager.create({ - message: message, - severity: severity, - date: new Date() - }, 'PartKeepr.Message'); - - this.messageLog.getStore().add(r); - } - }, - hideMessageLog: function () { - this.messageLog.hide(); - }, - showMessageLog: function () { - this.messageLog.show(); - }, - toggleMessageLog: function () { - if (this.messageLog.isHidden()) { - this.showMessageLog(); - } else { - this.hideMessageLog(); - } - - }, - getStatusbar: function () { - return this.statusBar; - }, - getSession: function () { - return this.getSessionManager().getSession(); - }, - setSession: function (session) { - if (session) { - this.getStatusbar().getConnectionButton().setConnected(); - } else { - this.getStatusbar().getConnectionButton().setDisconnected(); - this.setUsername(""); - } - + beforecollapse: Ext.bind( + function (obj) + { + this.hideMessageLog(); + return false; + }, + this) + } + }); + }, + log: function (message) + { + this.logMessage(message, "none"); + }, + logMessage: function (message, severity) + { + if (message != i18n("Ready.")) { + var r = Ext.ModelManager.create({ + message: message, + severity: severity, + date: new Date() + }, 'PartKeepr.Message'); + + this.messageLog.getStore().add(r); + } + }, + hideMessageLog: function () + { + this.messageLog.hide(); + }, + showMessageLog: function () + { + this.messageLog.show(); + }, + toggleMessageLog: function () + { + if (this.messageLog.isHidden()) { + this.showMessageLog(); + } else { + this.hideMessageLog(); + } + + }, + getStatusbar: function () + { + return this.statusBar; + }, + getSession: function () + { + return this.getSessionManager().getSession(); + }, + setSession: function (session) + { + if (session) { + this.getStatusbar().getConnectionButton().setConnected(); + } else { + this.getStatusbar().getConnectionButton().setDisconnected(); + this.setUsername(""); + } + }, /** * Sets the username. This should only be called from the login dialog. - * + * * Also updates the statusbar to reflect the username. - * + * * @param {string} username The username to set */ - setUsername: function (username) { - this.username = username; - this.getStatusbar().setCurrentUser(username); + setUsername: function (username) + { + this.username = username; + this.getStatusbar().setCurrentUser(username); }, /** - * Returns the current username + * Returns the current username * @returns {string} */ - getUsername: function () { - return this.username; - }, - formatCurrency: function (value) { - var format = Ext.util.Format; - format.currencyPrecision = PartKeepr.getApplication().getUserPreference("partkeepr.formatting.currency.numdecimals", 2); + getUsername: function () + { + return this.username; + }, + formatCurrency: function (value) + { + var format = Ext.util.Format; + format.currencyPrecision = PartKeepr.getApplication().getUserPreference( + "partkeepr.formatting.currency.numdecimals", 2); format.currencySign = PartKeepr.getApplication().getUserPreference("partkeepr.formatting.currency.symbol", "€"); - format.currencyAtEnd = PartKeepr.getApplication().getUserPreference("partkeepr.formatting.currency.currencySymbolAtEnd", true); - - if (PartKeepr.getApplication().getUserPreference("partkeepr.formatting.currency.thousandsSeparator", true) === true) { - // @todo This is hard-coded for now - format.thousandSeparator = ","; - } else { - format.thousandSeparator = ""; - } - + format.currencyAtEnd = PartKeepr.getApplication().getUserPreference( + "partkeepr.formatting.currency.currencySymbolAtEnd", true); + + if (PartKeepr.getApplication().getUserPreference("partkeepr.formatting.currency.thousandsSeparator", + true) === true) { + // @todo This is hard-coded for now + format.thousandSeparator = ","; + } else { + format.thousandSeparator = ""; + } + return format.currency(value); } }); -PartKeepr.getSession = function () { - alert("This should not be called."); - return "hli2ong0ktnise68p9f5nu6nk1"; +PartKeepr.getSession = function () +{ + alert("This should not be called."); + return "hli2ong0ktnise68p9f5nu6nk1"; }; -PartKeepr.log = function (message) { - PartKeepr.getApplication().log(message); +PartKeepr.log = function (message) +{ + PartKeepr.getApplication().log(message); }; /** * <p>This static method returns the instance of the application.</p> * @return {Object} The application -*/ -PartKeepr.getApplication = function () { - return PartKeepr.application; + */ +PartKeepr.getApplication = function () +{ + return PartKeepr.application; }; -PartKeepr.getBasePath = function () { - return document.getElementsByTagName('base')[0].href; +PartKeepr.getBasePath = function () +{ + return document.getElementsByTagName('base')[0].href; }; -PartKeepr.getImagePath = function () { - return "image.php"; +PartKeepr.getImagePath = function () +{ + return "image.php"; }; -PartKeepr.setMaxUploadSize = function (size) { - PartKeepr.maxUploadSize = size; +PartKeepr.setMaxUploadSize = function (size) +{ + PartKeepr.maxUploadSize = size; }; -PartKeepr.getMaxUploadSize = function () { - return PartKeepr.maxUploadSize; +PartKeepr.getMaxUploadSize = function () +{ + return PartKeepr.maxUploadSize; }; -PartKeepr.bytesToSize = function (bytes) { +PartKeepr.bytesToSize = function (bytes) +{ var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - if (bytes === 0) return 'n/a'; - var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)),10); + if (bytes === 0) { + return 'n/a'; + } + var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10); return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; }; -PartKeepr.setAvailableImageFormats = function (formats) { - PartKeepr.imageFormats = formats; +PartKeepr.setAvailableImageFormats = function (formats) +{ + PartKeepr.imageFormats = formats; }; -PartKeepr.getAvailableImageFormats = function () { - return PartKeepr.imageFormats; +PartKeepr.getAvailableImageFormats = function () +{ + return PartKeepr.imageFormats; }; -PartKeepr.serializeRecords = function (records) { - var finalData = []; - - for (var i=0;i<records.length;i++) { - finalData.push(records[i].data); - } - - return finalData; +PartKeepr.serializeRecords = function (records) +{ + var finalData = []; + + for (var i = 0; i < records.length; i++) { + finalData.push(records[i].data); + } + + return finalData; }; diff --git a/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig b/src/PartKeepr/FrontendBundle/Resources/views/index.html.twig @@ -83,6 +83,7 @@ '@PartKeeprFrontendBundle/Resources/public/js/Data/HydraProxy.js' '@PartKeeprFrontendBundle/Resources/public/js/Data/HydraReader.js' '@PartKeeprFrontendBundle/Resources/public/js/Data/store/PartCategoryStore.js' + '@PartKeeprFrontendBundle/Resources/public/js/Data/store/UserPreferenceStore.js' '@PartKeeprFrontendBundle/Resources/public/js/ExtJS/Enhancements/Ext.tree.View-missingMethods.js' '@PartKeeprFrontendBundle/Resources/public/js/ExtJS/Enhancements/Ext.form.Basic-AssociationSupport.js' '@PartKeeprFrontendBundle/Resources/public/js/ExtJS/Enhancements/Ext.ux.TreePicker-setValueWithObject.js'