From 568eb9170d61f661bfad04767cdd05e63fa1676a Mon Sep 17 00:00:00 2001 From: csoni Date: Thu, 20 Apr 2017 17:19:55 +0530 Subject: [PATCH] List folders that have been opened through the api Added button in MDMDeviceGeneralTab Created MDMManageSharedFolderContentPanel and MDMManageSharedFolderPanel to show a dialog with multi select hierarchy Created substore sharedfolder Added proxy and response handler to handel device response Used message class instead of object type, Override hierarchy tree , hierarchy loader and folder node ui --- js/MDM.js | 21 ++- js/data/JsonDeviceFolderReader.js | 41 +++++ js/data/JsonDeviceReader.js | 37 ++--- js/data/MDMDeviceFolderRecord.js | 21 +++ js/data/MDMDeviceFolderStore.js | 33 ++++ js/data/MDMDeviceProxy.js | 54 +++++++ js/data/MDMDeviceRecord.js | 39 +++-- js/data/MDMDeviceResponseHandler.js | 41 +++++ js/data/MDMDeviceStore.js | 5 +- js/data/MDMHierarchyTreeLoader.js | 57 +++++++ js/data/MDMRecord.js | 0 js/dialogs/MDMDeviceContentPanel.js | 21 ++- js/dialogs/MDMDeviceGeneralTab.js | 65 +++++++- .../MDMManageSharedFolderContentPanel.js | 36 +++++ js/dialogs/MDMManageSharedFolderPanel.js | 132 +++++++++++++++ js/settings/MDMSettingsWidget.js | 1 + js/ui/MDMFolderNodeUI.js | 151 ++++++++++++++++++ js/ui/MDMHierarchyTreePanel.js | 44 +++++ manifest.xml | 10 ++ php/class.pluginmdmmodule.php | 52 +++++- resources/css/mdm.css | 16 +- 21 files changed, 808 insertions(+), 69 deletions(-) create mode 100644 js/data/JsonDeviceFolderReader.js create mode 100644 js/data/MDMDeviceFolderRecord.js create mode 100644 js/data/MDMDeviceFolderStore.js create mode 100644 js/data/MDMDeviceProxy.js create mode 100644 js/data/MDMDeviceResponseHandler.js create mode 100644 js/data/MDMHierarchyTreeLoader.js delete mode 100644 js/data/MDMRecord.js create mode 100644 js/dialogs/MDMManageSharedFolderContentPanel.js create mode 100644 js/dialogs/MDMManageSharedFolderPanel.js create mode 100644 js/ui/MDMFolderNodeUI.js create mode 100644 js/ui/MDMHierarchyTreePanel.js diff --git a/js/MDM.js b/js/MDM.js index 0dc25fa..77199ce 100755 --- a/js/MDM.js +++ b/js/MDM.js @@ -16,6 +16,12 @@ Zarafa.plugins.mdm.MDM = Ext.extend(Zarafa.core.Plugin, { constructor : function(config) { config = config || {}; Zarafa.plugins.mdm.MDM.superclass.constructor.call(this, config); + + // Module information for MDM which will use in shadow store. + Zarafa.core.ModuleNames["IPM.MDM"] = { + list: 'pluginmdmmodule', + item: 'pluginmdmmodule' + } }, /** @@ -28,6 +34,7 @@ Zarafa.plugins.mdm.MDM = Ext.extend(Zarafa.core.Plugin, { this.registerInsertionPoint('context.settings.categories', this.createSettingCategory, this); this.registerInsertionPoint('settings.versioninformation', this.createVersionInfo, this); Zarafa.core.data.SharedComponentType.addProperty('mdm.dialog.mdmdevicecontentpanel'); + Zarafa.core.data.SharedComponentType.addProperty('mdm.dialog.mdmmanagesharedfoldercontentpanel'); Zarafa.plugins.mdm.MDM.superclass.initPlugin.apply(this, arguments); }, @@ -44,6 +51,9 @@ Zarafa.plugins.mdm.MDM = Ext.extend(Zarafa.core.Plugin, { case Zarafa.core.data.SharedComponentType['mdm.dialog.mdmdevicecontentpanel']: bid = 1; break; + case Zarafa.core.data.SharedComponentType['mdm.dialog.mdmmanagesharedfoldercontentpanel']: + bid = 1; + break; } return bid; }, @@ -57,7 +67,16 @@ Zarafa.plugins.mdm.MDM = Ext.extend(Zarafa.core.Plugin, { */ getSharedComponent : function (type, record) { - return Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel; + var component; + switch (type) { + case Zarafa.core.data.SharedComponentType['mdm.dialog.mdmdevicecontentpanel']: + component = Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel; + break; + case Zarafa.core.data.SharedComponentType['mdm.dialog.mdmmanagesharedfoldercontentpanel']: + component = Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel; + break; + } + return component; }, diff --git a/js/data/JsonDeviceFolderReader.js b/js/data/JsonDeviceFolderReader.js new file mode 100644 index 0000000..04ece92 --- /dev/null +++ b/js/data/JsonDeviceFolderReader.js @@ -0,0 +1,41 @@ +Ext.namespace('Zarafa.plugins.mdm.data'); + +/** + * @class Zarafa.plugins.mdm.data.JsonDeviceFolderReader + * @extends Zarafa.core.data.JsonReader + * + * This extension of the {@link Zarafa.core.data.JsonReader} supports + * {@link Zarafa.plugins.mdm.data.MDMDeviceStore stores} which can hold different type of + * {@link Zarafa.plugins.mdm.data.MDMDeviceRecord records}. + */ +Zarafa.plugins.mdm.data.JsonDeviceFolderReader = Ext.extend(Zarafa.core.data.JsonReader, { + + /** + * @cfg {Zarafa.core.data.RecordCustomObjectType} customObjectType The custom object type + * which represents the {@link Ext.data.Record records} which should be created using + * {@link Zarafa.core.data.RecordFactory#createRecordObjectByCustomType}. + */ + customObjectType: Zarafa.core.data.RecordCustomObjectType.MDM_Device_Folder, + + /** + * @constructor + * @param {Object} meta Metadata configuration options. + * @param {Object} recordType (optional) Optional Record type matches the type + * which must be read from response. If no type is given, it will use the + * record type for the {@link Zarafa.core.data.RecordCustomObjectType#ZARAFA_RECIPIENT}. + */ + constructor: function (meta, recordType) + { + meta = Ext.applyIf(meta || {}, { + id: 'folderid', + idProperty: 'folderid', + dynamicRecord: false + }); + + if (!Ext.isDefined(recordType)) { + recordType = Zarafa.core.data.RecordFactory.getRecordClassByCustomType(meta.customObjectType || this.customObjectType); + } + + Zarafa.plugins.mdm.data.JsonDeviceFolderReader.superclass.constructor.call(this, meta, recordType); + } +}); diff --git a/js/data/JsonDeviceReader.js b/js/data/JsonDeviceReader.js index 6f2b2c6..906310e 100644 --- a/js/data/JsonDeviceReader.js +++ b/js/data/JsonDeviceReader.js @@ -5,28 +5,21 @@ Ext.namespace('Zarafa.plugins.mdm.data'); * @extends Zarafa.core.data.JsonReader */ Zarafa.plugins.mdm.data.JsonCertificateReader = Ext.extend(Zarafa.core.data.JsonReader, { - /** - * @cfg {Zarafa.core.data.RecordCustomObjectType} customObjectType The custom object type - * which represents the {@link Ext.data.Record records} which should be created using - * {@link Zarafa.core.data.RecordFactory#createRecordObjectByCustomType}. - */ - customObjectType : Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, - /** - * @constructor - * @param {Object} meta Metadata configuration options. - * @param {Object} recordType (optional) Optional Record type matches the type - * which must be read from response. If no type is given, it will use the - * record type for the {@link Zarafa.core.data.RecordCustomObjectType#ZARAFA_MDM}. - */ - constructor : function(meta, recordType) - { - meta = Ext.applyIf(meta || {}, { - dynamicRecord : false - }); + /** + * @constructor + * @param {Object} meta Metadata configuration options. + * @param {Object} recordType (optional) Optional Record type matches the type + * which must be read from response. If no type is given, it will use the + * record type for the {@link Zarafa.core.mapi.ObjectType#MAPI_MDM}. + */ + constructor: function (meta, recordType) + { + meta = Ext.applyIf(meta || {}, { + dynamicRecord: false + }); + recordType = Zarafa.core.data.RecordFactory.getRecordClassByMessageClass('IPM.MDM'); - recordType = Zarafa.core.data.RecordFactory.getRecordClassByCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM); - - Zarafa.plugins.mdm.data.JsonCertificateReader.superclass.constructor.call(this, meta, recordType); - } + Zarafa.plugins.mdm.data.JsonCertificateReader.superclass.constructor.call(this, meta, recordType); + } }); diff --git a/js/data/MDMDeviceFolderRecord.js b/js/data/MDMDeviceFolderRecord.js new file mode 100644 index 0000000..f1fc2cf --- /dev/null +++ b/js/data/MDMDeviceFolderRecord.js @@ -0,0 +1,21 @@ +Ext.namespace('Zarafa.plugins.mdm'); + +/** + * @class Zarafa.plugins.mdm.data.MDMDeviceFolderRecordFields + * + * Array of default fields for the {@link Zarafa.plugins.mdm.data.MDMDeviceFolderRecord} object. + * These fields will always be added, regardless of the exact type of + * {@link Zarafa.plugins.mdm.data.MDMDeviceFolderRecord record}. + */ +Zarafa.plugins.mdm.data.MDMDeviceFolderRecordFields = [ + {name: 'store', type: 'string'}, + {name: 'folderid', type: 'string'}, + {name: 'name', type: 'string'}, + {name: 'type', type: 'int'}, + {name: 'flags', type: 'int'}, + {name: 'entryid', type: 'string'} +]; + +Zarafa.core.data.RecordCustomObjectType.addProperty('MDM_Device_Folder'); +Zarafa.core.data.RecordFactory.addFieldToCustomType(Zarafa.core.data.RecordCustomObjectType.MDM_Device_Folder, Zarafa.plugins.mdm.data.MDMDeviceFolderRecordFields); +Zarafa.core.data.RecordFactory.setBaseClassToCustomType(Zarafa.core.data.RecordCustomObjectType.MDM_Device_Folder, Zarafa.core.data.MAPIRecord); diff --git a/js/data/MDMDeviceFolderStore.js b/js/data/MDMDeviceFolderStore.js new file mode 100644 index 0000000..3981838 --- /dev/null +++ b/js/data/MDMDeviceFolderStore.js @@ -0,0 +1,33 @@ +Ext.namespace('Zarafa.plugins.mdm.data'); + +/** + * @class Zarafa.plugins.mdm.data.MDMDeviceFolderStore + * @extends Zarafa.core.data.MAPISubStore + * @xtype mdm.devicefolderstore + * Store specific for MDM Plugin which creates {@link Zarafa.plugins.mdm.MDMDeviceFolderStore record}. + */ +Zarafa.plugins.mdm.data.MDMDeviceFolderStore = Ext.extend(Zarafa.core.data.MAPISubStore, { + /** + * @constructor + * @param config Configuration object + */ + constructor: function (config) + { + config = config || {}; + + Ext.applyIf(config, { + autoLoad: true, + remoteSort: false, + reader: new Zarafa.plugins.mdm.data.JsonDeviceFolderReader(), + writer: new Zarafa.core.data.JsonWriter(), + proxy: new Zarafa.core.data.IPMProxy({ + listModuleName: 'pluginmdmmodule', + itemModuleName: 'pluginmdmmodule' + }) + }); + + Zarafa.plugins.mdm.data.MDMDeviceFolderStore.superclass.constructor.call(this, config); + } +}); + +Ext.reg('mdm.devicefolderstore', Zarafa.plugins.mdm.data.MDMDeviceFolderStore); \ No newline at end of file diff --git a/js/data/MDMDeviceProxy.js b/js/data/MDMDeviceProxy.js new file mode 100644 index 0000000..781dd44 --- /dev/null +++ b/js/data/MDMDeviceProxy.js @@ -0,0 +1,54 @@ +Ext.namespace('Zarafa.plugins.mdm.data'); + +/** + * @class Zarafa.plugins.mdm.data.MDMDeviceProxy + * @extends Zarafa.core.data.MAPIProxy + */ +Zarafa.plugins.mdm.data.MDMDeviceProxy = Ext.extend(Zarafa.core.data.MAPIProxy, { + + /** + * @constructor + * @param {Object} config Configuration object + */ + constructor: function (config) + { + config = config || {}; + Ext.applyIf(config, { + listModuleName: 'pluginmdmmodule', + itemModuleName: 'pluginmdmmodule' + }); + + Zarafa.plugins.mdm.data.MDMDeviceProxy.superclass.constructor.call(this, config); + }, + + /** + * This will create a {@link Zarafa.core.data.ProxyResponseHandler ProxyResponseHandler} object + * which will be used by the {@link Zarafa.core.data.ResponseRouter ResponseRouter} when the + * response for the given request has returned. + * + * @param {String} modulename The modulename which is being accessed with this request + * @param {Zarafa.core.Actions} serverAction The action to perform on the server. + * @param {Ext.data.Api.action} action name of the action to perform. + * @param {Ext.data.Record[]} records list of records to operate on. + * @param {Object} parameters object containing user parameters such as range (pagination) information, sorting information, etc. + * @param {Ext.data.DataReader} reader data reader. Converts raw JavaScript objects (in our case) to instances of {@link Ext.data.Record} + * @param {Function} callback call back function to call when the request has finished successfully. + * @param {Object} scope scope for the call back function. + * @param {Object} args arguments object. This will be passed to the call back function on successful read. + * @return {Object} An instance of the {@link Zarafa.plugins.mdm.data.MDMDeviceResponseHandler ProxyResponseHandler} + * which should be used for this request. + * @private + */ + getResponseHandlerForRequest: function (modulename, serverAction, action, records, parameters, reader, callback, scope, args) + { + return new Zarafa.plugins.mdm.data.MDMDeviceResponseHandler({ + proxy: this, + action: action, + reader: reader, + sendRecords: records, + options: args, + callback: callback, + scope: scope + }); + } +}); diff --git a/js/data/MDMDeviceRecord.js b/js/data/MDMDeviceRecord.js index 64c22a9..e73ae49 100644 --- a/js/data/MDMDeviceRecord.js +++ b/js/data/MDMDeviceRecord.js @@ -1,5 +1,10 @@ Ext.namespace('Zarafa.plugins.mdm'); +/** + * @class Zarafa.plugins.mdm.data.MDMDeviceRecordFields Array of {@link Ext.data.Field field} configurations for the + * {@link Zarafa.plugins.mdm.data.MDMDeviceRecord record} object. + * @private + */ Zarafa.plugins.mdm.data.MDMDeviceRecordFields = [ {name: 'entryid', type: 'string'}, {name: 'devicetype', type: 'string'}, @@ -12,30 +17,22 @@ Zarafa.plugins.mdm.data.MDMDeviceRecordFields = [ {name: 'lastupdatetime', type: 'date', dateFormat: 'timestamp'}, {name: 'wipestatus', type: 'string'}, {name: 'policyname', type: 'string'}, - {name: 'totalfolders', type: 'string'}, + {name: 'sharedfolders', type: 'string'}, {name: 'shortfolderids', type: 'string'}, - {name: 'synchronizedfolders', type: 'string'}, - {name: 'emailsfolder', type: 'string'}, - {name: 'contactsfolder', type: 'string'}, - {name: 'tasksfolder', type: 'string'}, - {name: 'calendarsfolder', type: 'string'}, - {name: 'notesfolder', type: 'string'}, + {name: 'synchronizedfolders', type: 'string', defaultValue:'0'}, + {name: 'emailsfolder', type: 'string', defaultValue:'0'}, + {name: 'contactsfolder', type: 'string', defaultValue:'0'}, + {name: 'tasksfolder', type: 'string', defaultValue:'0'}, + {name: 'calendarsfolder', type: 'string', defaultValue:'0'}, + {name: 'notesfolder', type: 'string', defaultValue:'0'}, {name: 'koeversion', type: 'string'}, {name: 'koebuild', type: 'string'}, - {name: 'koebuilddate', type: 'date', dateFormat: 'timestamp'} + {name: 'koebuilddate', type: 'date', dateFormat: 'timestamp'}, + {name: 'message_class', type: 'string', defaultValue:"IPM.MDM"} ]; -/** - * - */ + Zarafa.plugins.mdm.data.MDMDeviceRecord = Ext.extend(Zarafa.core.data.IPMRecord, {}); -Zarafa.core.data.RecordCustomObjectType.addProperty('ZARAFA_MDM'); -Zarafa.core.data.RecordFactory.addFieldToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, Zarafa.plugins.mdm.data.MDMDeviceRecordFields); - -Zarafa.core.data.RecordFactory.addListenerToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, 'createphantom', function(record) -{ - // Phantom records must always be marked as opened (they contain the full set of data) - record.afterOpen(); -}); - -Zarafa.core.data.RecordFactory.setBaseClassToCustomType(Zarafa.core.data.RecordCustomObjectType.ZARAFA_MDM, Zarafa.plugins.mdm.data.MDMDeviceRecord); +Zarafa.core.data.RecordFactory.addFieldToMessageClass('IPM.MDM', Zarafa.plugins.mdm.data.MDMDeviceRecordFields); +Zarafa.core.data.RecordFactory.setBaseClassToMessageClass('IPM.MDM', Zarafa.plugins.mdm.data.MDMDeviceRecord); +Zarafa.core.data.RecordFactory.setSubStoreToMessageClass('IPM.MDM', 'sharedfolders', Zarafa.plugins.mdm.data.MDMDeviceFolderStore); diff --git a/js/data/MDMDeviceResponseHandler.js b/js/data/MDMDeviceResponseHandler.js new file mode 100644 index 0000000..d627d3b --- /dev/null +++ b/js/data/MDMDeviceResponseHandler.js @@ -0,0 +1,41 @@ +Ext.namespace('Zarafa.plugins.mdm.data'); + +/** + * @class Zarafa.plugins.mdm.data.MDMDeviceResponseHandler + * @extends Zarafa.core.data.ProxyResponseHandler + * + * A Simple implementation for a {@link Zarafa.plugins.mdm.data.MDMDeviceResponseHandler ResponseHandler}. + * This one can only be used by {@link Ext.data.DataProxy proxies} which wish to handle a Response + * to their Request. + * + * This implementation limits itself to firing an {@link Ext.data.DataProxy#exception exception} + * on error, and calling a callback function when all processing has been completed. + */ +Zarafa.plugins.mdm.data.MDMDeviceResponseHandler = Ext.extend(Zarafa.core.data.ProxyResponseHandler, { + + /** + * Handles the list response. Gathers the stores from the response data, converts each entry + * into a {@link Zarafa.core.MAPIStore MAPIStore} and pushes them into the collectedItems. + * @param {Object} data The response object belonging to the given command. + * @return {Boolean} False when action could not be handled successfully. This will + * not cancel the transaction itself, but rather causes the 'success' argument for the + * {@link #done} function to be false. + */ + doOpen: function(response) + { + this.receivedRecords = this.readRecordsFromResponse(response, 'item'); + }, + + /** + * Handles the list response. Gathers the stores from the response data, converts each entry + * into a {@link Zarafa.core.MAPIStore MAPIStore} and pushes them into the collectedItems. + * @param {Object} data The response object belonging to the given command. + * @return {Boolean} False when action could not be handled successfully. This will + * not cancel the transaction itself, but rather causes the 'success' argument for the + * {@link #done} function to be false. + */ + doList: function(response) + { + this.receivedRecords = this.readRecordsFromResponse(response, 'item'); + } +}); diff --git a/js/data/MDMDeviceStore.js b/js/data/MDMDeviceStore.js index a9f7ea1..fad7075 100644 --- a/js/data/MDMDeviceStore.js +++ b/js/data/MDMDeviceStore.js @@ -20,10 +20,7 @@ Zarafa.plugins.mdm.data.MDMDeviceStore = Ext.extend(Zarafa.core.data.ListModuleS remoteSort: false, reader : new Zarafa.plugins.mdm.data.JsonCertificateReader(), writer : new Zarafa.core.data.JsonWriter(), - proxy : new Zarafa.core.data.IPMProxy({ - listModuleName: 'pluginmdmmodule', - itemModuleName: 'pluginmdmmodule' - }) + proxy : new Zarafa.plugins.mdm.data.MDMDeviceProxy() }); Zarafa.plugins.mdm.data.MDMDeviceStore.superclass.constructor.call(this, config); diff --git a/js/data/MDMHierarchyTreeLoader.js b/js/data/MDMHierarchyTreeLoader.js new file mode 100644 index 0000000..8eb159c --- /dev/null +++ b/js/data/MDMHierarchyTreeLoader.js @@ -0,0 +1,57 @@ +Ext.namespace('Zarafa.hierarchy.data'); + +/** + * @class Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader + * @extends Zarafa.hierarchy.data.HierarchyTreeLoader + * + * A Special treeloader to be used by the {@link Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader MDMHierarchyTree}. + * This wil dynamically load the child nodes for a given node by obtaining the subfolders of + * the folder related to the given node. + */ +Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader = Ext.extend(Zarafa.hierarchy.data.HierarchyTreeLoader, { + + /** + * @constructor + * @param {Object} config Configuration object + */ + constructor : function(config) + { + Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader.superclass.constructor.call(this, config); + }, + + /** + * Add extra attributes for a new {@link Zarafa.hierarchy.ui.FolderNode folderNode} which is about + * to be created. This will check the {@link Zarafa.hierarchy.ui.FolderNode#folder folder} to + * see what properties must be set. + * + * Override to provide (@link Zarafa.plugins.mdm.ui.MDMFolderNodeUI MDMFolderNodeUI} to ui provider + * @param {Object} attr The attributes which will be used to create the node + * @return {Zarafa.hierarchy.ui.FolderNode} The created node + */ + createNode : function(attr) + { + var folder = attr.folder; + + if (folder) { + if (attr.nodeType === 'rootfolder') { + attr.extendedDisplayName = this.tree.hasFilter(); + } + + // To uniquely identify the favorites tree nodes we append the "favorites-" key word with node id + // when the node is created. + attr.id = folder.isFavoritesFolder() ? "favorites-" + folder.get('entryid') : folder.get('entryid'); + if (folder.isFavoritesRootFolder()) { + attr.leaf = folder.get('assoc_content_count') === 0; + } else { + attr.leaf = !folder.get('has_subfolder'); + } + + attr.uiProvider = Zarafa.plugins.mdm.ui.MDMFolderNodeUI; + attr.expanded = this.tree.isFolderOpened(folder); + attr.allowDrag = !folder.isDefaultFolder(); + } + + // call parent of parent because of parent class will change ui provider + return Zarafa.hierarchy.data.HierarchyTreeLoader.superclass.createNode.apply(this, arguments); + } +}); diff --git a/js/data/MDMRecord.js b/js/data/MDMRecord.js deleted file mode 100644 index e69de29..0000000 diff --git a/js/dialogs/MDMDeviceContentPanel.js b/js/dialogs/MDMDeviceContentPanel.js index 30d7709..497ac7e 100644 --- a/js/dialogs/MDMDeviceContentPanel.js +++ b/js/dialogs/MDMDeviceContentPanel.js @@ -2,12 +2,12 @@ Ext.namespace('Zarafa.plugins.mdm.dialogs'); /** * @class Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel - * @extends Zarafa.core.ui.ContentPanel + * @extends Zarafa.core.ui.RecordContentPanel * @xtype mdmplugin.devicecontentpanel * * The content panel which is use to show device detail panel. */ -Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel = Ext.extend(Zarafa.core.ui.ContentPanel, { +Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel = Ext.extend(Zarafa.core.ui.RecordContentPanel, { /** * @constructor @@ -16,19 +16,24 @@ Zarafa.plugins.mdm.dialogs.MDMDeviceContentPanel = Ext.extend(Zarafa.core.ui.Con constructor: function (config) { config = config || {}; - var isKOE = config.record && config.record.get('koeversion') ? true : false; + var isKOE = config.record && config.record.get('koeversion') ? true : false; Ext.applyIf(config, { xtype: 'mdmplugin.devicecontentpanel', modal: true, title: dgettext('plugin_mdm', config.record.get('devicetype')), - layout : 'fit', - stateful : false, - width : isKOE ? 440 : 405, - height : isKOE ? 395 : 360, + recordComponentPluginConfig: Ext.applyIf(config.recordComponentPluginConfig || {}, { + allowWrite: true, + useShadowStore: true + }), + layout: 'fit', + stateful: false, + showLoadMask: false, + width: isKOE ? 440 : 405, + height: isKOE ? 450 : 420, items: [{ xtype: 'mdmplugin.mdmdevicepanel', record: config.record, - isKoe : isKOE, + isKoe: isKOE, buttons: [{ text: _('Ok'), handler: this.onOk, diff --git a/js/dialogs/MDMDeviceGeneralTab.js b/js/dialogs/MDMDeviceGeneralTab.js index e26daf9..e46b0c6 100644 --- a/js/dialogs/MDMDeviceGeneralTab.js +++ b/js/dialogs/MDMDeviceGeneralTab.js @@ -12,7 +12,7 @@ Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab = Ext.extend(Ext.form.FormPanel, /** * @cfg {Boolean} isKoe True if device has Kopano Outlook Extension information. */ - isKoe : false, + isKoe: false, /** * @constructor @@ -54,7 +54,7 @@ Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab = Ext.extend(Ext.form.FormPanel, createDeviceInfoPanel: function (config) { return { - cls : 'mdm-device-panel', + cls: 'mdm-device-panel', defaultType: 'displayfield', defaults: { disabled: true @@ -89,7 +89,7 @@ Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab = Ext.extend(Ext.form.FormPanel, createFolderInfoPanel: function () { return { - cls : 'mdm-device-panel mdm-field-sep', + cls: 'mdm-device-panel mdm-field-sep', defaultType: 'displayfield', items: [{ cls: 'mdm-display-name', @@ -104,7 +104,7 @@ Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab = Ext.extend(Ext.form.FormPanel, xtype: 'fieldset', layout: 'form', labelWidth: 140, - cls : 'mdm-synchronize-panel', + cls: 'mdm-synchronize-panel', defaultType: 'displayfield', defaults: { labelSeparator: '', @@ -126,7 +126,48 @@ Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab = Ext.extend(Ext.form.FormPanel, }, { fieldLabel: _('Tasks'), name: 'tasksfolder' - }] + }, + this.createSharedFolderInfoPanel() + ] + }] + }; + }, + + /** + * Function which is use to create shared folders panel + * @returns {Object} Configuration object for the panel which shows folders properties + */ + createSharedFolderInfoPanel: function () + { + return { + xtype: 'panel', + border: false, + cls: 'mdm-synchronize-shared-panel', + height: 50, + disabled: false, + layout: { + type: 'hbox', + align: 'stretch', + pack: 'start' + }, + items: [{ + layout: 'form', + border: false, + items: [{ + xtype: 'displayfield', + fieldLabel: 'Shared Folders', + disabled: true, + name : 'sharedfolders' + }], + flex: 1 + }, { + xtype: 'button', + text: dgettext('plugin_mdm', 'Managed shared Folders'), + cls: 'mdm-managesharedfolder-button', + listeners: { + click: this.onClickManageSharedFolder, + scope: this + } }] }; }, @@ -142,13 +183,25 @@ Zarafa.plugins.mdm.dialogs.MDMDeviceGeneralTab = Ext.extend(Ext.form.FormPanel, /** * Function which handles the after render event of status field. - * Which is use to set the the display name for the given Provisioning Status into given field + * Which is use to set the display name for the given Provisioning Status into given field * @param {Ext.form.TextField} statusField text field */ onAfterRenderStatus: function (statusField) { var status = parseInt(this.record.get("wipestatus")); statusField.setValue(Zarafa.plugins.mdm.data.ProvisioningStatus.getDisplayName(status)); + }, + + /** + * Function which handles the click event of manage shared folder button. + * It will open {@link Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel dialog} + */ + onClickManageSharedFolder: function () + { + Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['mdm.dialog.mdmmanagesharedfoldercontentpanel'], undefined, { + manager: Ext.WindowMgr, + record: this.dialog.record + }); } }); diff --git a/js/dialogs/MDMManageSharedFolderContentPanel.js b/js/dialogs/MDMManageSharedFolderContentPanel.js new file mode 100644 index 0000000..b77d673 --- /dev/null +++ b/js/dialogs/MDMManageSharedFolderContentPanel.js @@ -0,0 +1,36 @@ +Ext.namespace('Zarafa.plugins.mdm.dialogs'); + +/** + * @class Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel + * @extends Zarafa.core.ui.ContentPanel + * @xtype zarafa.managesharedfoldercontentpanel + * + * This will display a {@link Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel contentpanel} + * to show {@link Zarafa.core.data.IPFRecord folders} which are shared with device. + */ +Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel = Ext.extend(Zarafa.core.ui.ContentPanel, { + + /** + * @constructor + * @param config Configuration structure + */ + constructor: function (config) { + config = config || {}; + + Ext.applyIf(config, + { + xtype: 'mdm.managesharedfoldercontentpanel', + layout: 'fit', + title: dgettext('plugin_mdm','Manage Shared Folder'), + width: 300, + height: 350, + items: [{ + xtype: 'mdm.managesharedfolderpanel' + }] + }); + + Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel.superclass.constructor.call(this, config); + } +}); + +Ext.reg('mdm.managesharedfoldercontentpanel', Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderContentPanel); diff --git a/js/dialogs/MDMManageSharedFolderPanel.js b/js/dialogs/MDMManageSharedFolderPanel.js new file mode 100644 index 0000000..b7dd667 --- /dev/null +++ b/js/dialogs/MDMManageSharedFolderPanel.js @@ -0,0 +1,132 @@ +Ext.namespace('Zarafa.plugins.mdm.dialogs'); + +/** + * @class Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel + * @extends Ext.Panel + * @xtype mdm.managesharedfolderpanel + * + * Panel for users to show the {@link Zarafa.core.data.IPFRecord folders} which are shared with device + */ +Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel = Ext.extend(Ext.Panel, { + + /** + * @constructor + * @param {Object} config Configuration structure + */ + constructor: function (config) + { + config = config || {}; + + Ext.applyIf(config, { + xtype: 'mdm.managesharedfolderpanel', + layout: { + type: 'fit', + align: 'stretch' + }, + border: false, + header: false, + items: [ + this.createTreePanel() + ], + buttonAlign: 'right', + buttons: [{ + text: _('Apply'), + ref: '../okButton', + cls: 'zarafa-action', + scope: this + }, { + text: _('Cancel'), + ref: '../cancelButton', + handler: this.onCancel, + scope: this + }] + }); + + Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel.superclass.constructor.call(this, config); + }, + + /** + * Creates a {@link Zarafa.hierarchy.ui.Tree treepanel} + * which contains all the {@link Zarafa.hierarchy.data.MAPIFolderRecord folders} + * on which search get perform. + * @return {Object} Configuration object for the tree panel. + * @private + */ + createTreePanel: function () + { + return { + xtype: 'panel', + layout : 'form', + defaults: { + cls : 'mdm-create-tree-panel-item' + }, + border: false, + flex: 1, + items: [{ + xtype: 'displayfield', + hideLabel : true, + value: dgettext('plugin_mdm','Select folders to sync on your device') + }, { + xtype: 'mdm.hierarchytree', + autoScroll : true, + nodeConfig : { + checked : false + }, + multiSelect: true, + hideShowAllFolders: true, + border: true, + treeSorter: true, + bbarConfig: { + hidden: true + }, + enableDD: false, + anchor: '100% 90%', + ref: '../hierarchyTree' + }] + }; + }, + + /** + * Initialize the events + * @private + */ + initEvents: function () + { + Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel.superclass.initEvents.apply(this, arguments); + this.mon(this.hierarchyTree, 'load', this.onTreeNodeLoad, this); + }, + + /** + * Fired when the {@link Zarafa.hierarchy.ui.Tree Tree} fires the {@link Zarafa.hierarchy.ui.Tree#load load} + * event. This function will try to select those {@link Ext.tree.TreeNode TreeNode} in + * {@link Zarafa.hierarchy.ui.Tree Tree} which was shared with respective device. When the given node is not loaded yet, it will try again + * later when the event is fired again. + * + * @private + */ + onTreeNodeLoad: function () + { + var subStore = this.dialog.record.getSubStore('sharedfolders'); + var folders = subStore.getRange(); + folders.forEach(function (folder) { + var node = this.hierarchyTree.getNodeById(folder.get('entryid')); + if (Ext.isDefined(node)) { + if(node.hasChildNodes()){ + node.expand(); + } + node.getUI().toggleCheck(true) + } + }, this); + }, + + /** + * Action handler when the user presses the "Cancel" button. + * This will close the panel. + */ + onCancel: function () + { + this.dialog.close(); + } +}); + +Ext.reg('mdm.managesharedfolderpanel', Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel); \ No newline at end of file diff --git a/js/settings/MDMSettingsWidget.js b/js/settings/MDMSettingsWidget.js index 899fea4..566ab12 100644 --- a/js/settings/MDMSettingsWidget.js +++ b/js/settings/MDMSettingsWidget.js @@ -207,6 +207,7 @@ Zarafa.plugins.mdm.settings.MDMSettingsWidget = Ext.extend(Zarafa.settings.ui.Se onRowDblClick : function (grid, rowIndex) { var record = grid.getStore().getAt(rowIndex); + record.opened = false; Zarafa.core.data.UIFactory.openLayerComponent(Zarafa.core.data.SharedComponentType['mdm.dialog.mdmdevicecontentpanel'], undefined, { manager : Ext.WindowMgr, record : record diff --git a/js/ui/MDMFolderNodeUI.js b/js/ui/MDMFolderNodeUI.js new file mode 100644 index 0000000..07681ff --- /dev/null +++ b/js/ui/MDMFolderNodeUI.js @@ -0,0 +1,151 @@ +Ext.namespace('Zarafa.plugins.mdm.ui'); + + +/** + * @class Zarafa.plugins.mdm.ui.MDMFolderNodeUI + * @extends Zarafa.hierarchy.ui.FolderNodeUI + * + * {@link Zarafa.hierarchy.ui.FolderNodeUI} has limitation that it can add + * (@link Ext.form.Checkbox check box} preceded to calendar item only. + * So, It will add (@link Ext.form.Checkbox check box} preceded to all context items. + */ +Zarafa.plugins.mdm.ui.MDMFolderNodeUI = Ext.extend(Zarafa.hierarchy.ui.FolderNodeUI, { + + /** + * Function will render {@link Zarafa.hierachy.ui.FolderNode FolderNode} based on modified template for + * our custom needs. + * @param {Zarafa.hierarchy.ui.FolderNode} node tree node. + * @param {Object} config config object of {@link Zarafa.hierarchy.ui.FolderNode FolderNode}. + * @param {Ext.Element} targetNode element in which {@link Zarafa.hierarchy.ui.FolderNode FolderNode} will be rendered. + * @param {Boolean} bulkRender + */ + renderElements : function(node, config, targetNode, bulkRender) + { + // add some indent caching, this helps performance when rendering a large tree + this.indentMarkup = node.parentNode ? node.parentNode.ui.getChildIndent() : ''; + + var scheme; + var cb = Ext.isBoolean(config.checked); + var isCalenderNode = config.folder.isCalendarFolder(); + var calendarSVGIcon = ''; + + if (isCalenderNode) { + var calendarContextModel = node.getOwnerTree().model; + + // We started providing color choosing facility to all the calendar tree-nodes. + // CalendarContextModel is responsible for this facility. + // There is no CalendarContextModel available in the case where that particular + // calendar-tree-node doesn't belongs to MultiSelectHierarchyTree. + // So, simply made that ContextModel available to current HierarchyTree. + if (!calendarContextModel) { + var calendarContext = container.getContextByName('calendar'); + calendarContextModel = calendarContext.getModel(); + node.getOwnerTree().model = calendarContextModel; + } + + scheme = calendarContextModel.getColorScheme(config.folder.get('entryid')); + + // Get the scheme base only if we are able to get scheme successfully, + // otherwise let it be undefined instead of a JS fatal error. + if(scheme && scheme.base) { + calendarSVGIcon = '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' ; + } + } + + var icon = '', + nel, + href = config.href ? config.href : Ext.isGecko ? "" : "#", + buf = '
  • ' + + '
    ' + + // indent space + '' + this.indentMarkup + "" + + // expand icon + '' + + // checkbox + (cb ? '' : '/>') : '') + + // node icon + (isCalenderNode ? calendarSVGIcon : icon) + + // node element (this.elNode) + '" + + // hierarchy node text (this.textNode) + '' + (node.tpl ? node.tpl.apply(config) : node.text) + '' + + // counter node (this.counterNode) + '' + + ''+ + "" + + "
    " + + '' + + "
  • "; + + if (bulkRender !== true && node.nextSibling && (nel = node.nextSibling.ui.getEl())) { + this.wrap = Ext.DomHelper.insertHtml("beforeBegin", nel, buf); + }else{ + this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf); + } + + this.elNode = this.wrap.childNodes[0]; + this.ctNode = this.wrap.childNodes[1]; + var cs = this.elNode.childNodes; + this.indentNode = cs[0]; + this.ecNode = cs[1]; + this.iconNode = cs[2]; + var index = 3; + if (cb) { + this.checkbox = cs[2]; + this.iconNode = cs[3]; + + // Get child elements of caledar icon which is used to register in drag and drop manager. + var groupContainerNode = this.iconNode.childNodes[0]; + if (Ext.isDefined(groupContainerNode)) { + var groupNode = groupContainerNode.childNodes[0]; + var rectNode = groupNode.childNodes[0]; + var pathNode = groupContainerNode.childNodes[1]; + this.calendarSVGIconChilds = [rectNode, pathNode]; + } + index++; + } + this.anchor = cs[index]; + this.textNode = cs[index].firstChild; + + this.counterNode = cs[index].firstChild.nextSibling; + this.folderOwnerNode = this.counterNode.nextSibling; + // Apply some optional CSS classes + var elNode = Ext.get(this.elNode); + var iconNode = Ext.get(this.iconNode); + var containerNode = Ext.get(this.wrap); + var textNode = Ext.get(this.textNode); + if (isCalenderNode) { + textNode.addClass('zarafa-hierarchy-node-color'); + } + if (!Ext.isEmpty(config.cls)) { + elNode.addClass(config.cls); + } + + if (config.icon) { + iconNode.addClass('x-tree-node-inline-icon'); + } + + if (config.iconCls) { + iconNode.addClass(config.iconCls); + } + + if (!Ext.isEmpty(config.containerCls)) { + containerNode.addClass(config.containerCls); + } + + this.updateCounter(node); + this.showFolderOwner(node); + } +}); diff --git a/js/ui/MDMHierarchyTreePanel.js b/js/ui/MDMHierarchyTreePanel.js new file mode 100644 index 0000000..f0aa48a --- /dev/null +++ b/js/ui/MDMHierarchyTreePanel.js @@ -0,0 +1,44 @@ +Ext.namespace('Zarafa.plugins.mdm.ui'); + +/** + * @class Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel + * @extends Zarafa.hierarchy.ui.Tree + * @xtype mdm.hierarchytree + * + * MDMHierarchyTreePanel for hierachy list in the + * {@link Zarafa.plugins.mdm.dialogs.MDMManageSharedFolderPanel manageSharedFolderPanel}. + */ +Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel = Ext.extend(Zarafa.hierarchy.ui.Tree, { + + /** + * @constructor + * @param {Object} config Configuration object + */ + constructor : function(config) + { + Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel.superclass.constructor.call(this, config); + }, + + /** + * Function will initialize {@link Zarafa.hierarchy.ui.Tree Tree} and creates a + * {@link Zarafa.common.ui.LoadMask} if {@link Zarafa.hierarchy.ui.Tree Tree} is intantiated as full tree. + * @protected + */ + initComponent : function() + { + // Intialize the loader + if (!this.loader) { + this.loader = new Zarafa.plugins.mdm.data.MDMHierarchyTreeLoader({ + tree : this, + store : this.store, + nodeConfig : this.nodeConfig, + deferredLoading : this.deferredLoading + }); + } + + // call parent + Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel.superclass.initComponent.apply(this, arguments); + } +}); + +Ext.reg('mdm.hierarchytree', Zarafa.plugins.mdm.ui.MDMHierarchyTreePanel); diff --git a/manifest.xml b/manifest.xml index 80c35a7..fa102d2 100755 --- a/manifest.xml +++ b/manifest.xml @@ -26,18 +26,28 @@ js/mdm.js js/mdm-debug.js js/MDM.js + js/data/MDMDeviceFolderStore.js + js/data/MDMDeviceFolderRecord.js + js/data/JsonDeviceFolderReader.js js/data/MDMResponseHandler.js js/data/MDMDeviceRecord.js js/data/JsonDeviceReader.js js/data/MDMDeviceStore.js js/data/ProvisioningStatus.js + js/data/MDMDeviceProxy.js + js/data/MDMDeviceResponseHandler.js + js/data/MDMHierarchyTreeLoader.js js/settings/MDMSettingsWidget.js js/settings/MDMSettingsCategory.js js/dialogs/MDMDeviceContentPanel.js js/dialogs/MDMDeviceGeneralTab.js js/dialogs/MDMDevicePanel.js js/dialogs/MDMDeviceDetailsTab.js + js/dialogs/MDMManageSharedFolderContentPanel.js + js/dialogs/MDMManageSharedFolderPanel.js js/ui/Renderers.js + js/ui/MDMFolderNodeUI.js + js/ui/MDMHierarchyTreePanel.js resources/css/mdm.css diff --git a/php/class.pluginmdmmodule.php b/php/class.pluginmdmmodule.php index 7feeaeb..22ce717 100755 --- a/php/class.pluginmdmmodule.php +++ b/php/class.pluginmdmmodule.php @@ -171,6 +171,20 @@ class PluginMDMModule extends Module $this->addActionData('list', $data); $GLOBALS['bus']->addData($this->getResponseData()); break; + + case 'open': + $data = array(); + $rawData = $this->getDevices(); + foreach($rawData as $device){ + if($device->data['deviceid'] === $actionData['entryid']) { + $data['props'] = $this->getDeviceProps($device->data); + $data["sharedfolders"] = array("item" => $this->getAdditionalFolderList($actionData['entryid'])); + } + } + $item = array("item" => $data); + $this->addActionData('item', $item); + $GLOBALS['bus']->addData($this->getResponseData()); + break; default: $this->handleUnknownActionType($actionType); } @@ -212,6 +226,7 @@ class PluginMDMModule extends Module 'lastsynctime', 'lastupdatetime', 'wipestatus', 'policyname', 'koeversion', 'koebuild', 'koebuilddate']; $item['entryid'] = $device['deviceid']; + $item['message_class'] = "IPM.MDM"; foreach ($propsList as $prop) { if (isset($device[$prop])) { $item[$prop] = $device[$prop]; @@ -262,11 +277,11 @@ class PluginMDMModule extends Module $synchronizedFolders += $value; $syncFoldersProps[strtolower($key) . 'folder'] = $value; } - - - $syncFoldersProps["totalfolders"] = count($folders); + $client = $this->getSoapClient(); + $items = $client->AdditionalFolderList($device['deviceid']); + $syncFoldersProps['sharedfolders'] = count($items); $syncFoldersProps["shortfolderids"] = $device['hasfolderidmapping'] ? dgettext('plugin_mdm', "Yes") : dgettext('plugin_mdm', "No"); - $syncFoldersProps['synchronizedfolders'] = $synchronizedFolders; + $syncFoldersProps['synchronizedfolders'] = $synchronizedFolders + count($items); return $syncFoldersProps; } @@ -309,5 +324,34 @@ class PluginMDMModule extends Module } return $folderType; } + + /** + * Function which is use to get list of additional folders which was shared with given device + * @param string $devid device id + * @return array has list of properties related to shared folders + */ + function getAdditionalFolderList($devid) + { + $stores = $GLOBALS["mapisession"]->getAllMessageStores(); + $client = $this->getSoapClient(); + $items = $client->AdditionalFolderList($devid); + $data = array(); + foreach ($items as $item) + { + foreach ($stores as $store) + { + try { + $entryid = mapi_msgstore_entryidfromsourcekey($store, hex2bin($item->folderid)); + } catch (MAPIException $me) { + continue; + } + } + if (isset($entryid)) { + $item->entryid = bin2hex($entryid); + } + array_push($data, array("props" => $item)); + } + return $data; + } }; ?> diff --git a/resources/css/mdm.css b/resources/css/mdm.css index dc57b9b..735c275 100755 --- a/resources/css/mdm.css +++ b/resources/css/mdm.css @@ -2,7 +2,6 @@ background-image:url(../icons/mdm_icon.png) !important; } - .mdm-devicepanel.x-panel.tabpanel-container > .x-panel-bwrap > .x-panel-body { @@ -17,7 +16,6 @@ padding: 0!important; } - .mdm-display-name { font-weight: bold !important; padding: 4px 0 2px 0; @@ -36,5 +34,17 @@ .mdm-synchronize-panel { border: 0px; margin-left: 10px; - padding: 0px; + padding: 9px 0 0 0; +} + +.mdm-managesharedfolder-button { + padding-right: 10px; +} + +.mdm-create-tree-panel-item { + margin: 0 0 5px 0; +} + +.mdm-synchronize-shared-panel { + padding-top: 9px; } \ No newline at end of file