From b2f733c4d524289d0a3800f45d1575d02140eea6 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Wed, 3 Jul 2013 16:27:18 +0000 Subject: [PATCH] a few more steps towards a new admin --- admin/inc/class.admin_ui.inc.php | 170 +++++++++++++++++++++++++++++- admin/js/app.js | 45 +++++++- admin/lang/egw_de.lang | 3 +- admin/lang/egw_en.lang | 1 + admin/templates/default/app.css | 17 +++ admin/templates/default/index.xet | 54 +++++++++- 6 files changed, 279 insertions(+), 11 deletions(-) diff --git a/admin/inc/class.admin_ui.inc.php b/admin/inc/class.admin_ui.inc.php index 00b2a0c95b..1f277175cc 100644 --- a/admin/inc/class.admin_ui.inc.php +++ b/admin/inc/class.admin_ui.inc.php @@ -25,6 +25,13 @@ class admin_ui 'index' => true, ); + /** + * Reference to global accounts object + * + * @var accounts + */ + private static $accounts; + /** * New index page * @@ -36,11 +43,156 @@ class admin_ui $tpl = new etemplate_new('admin.index'); $content = array(); + $content['admin_nm'] = array( + 'get_rows' => 'admin_ui::get_users', + 'no_cat' => true, + 'no_filter2' => true, + 'filter_label' => 'Group', + 'filter_no_lang' => true, + 'lettersearch' => true, + 'order' => 'account_lid', + 'sort' => 'ASC', + 'row_id' => 'account_id', + 'default_cols' => '!account_id,account_created', + 'actions' => self::user_actions(), + ); //$content['msg'] = 'Hi Ralf ;-)'; $sel_options['tree'] = $this->tree_data(); + $sel_options['filter'] = array('' => lang('All')); + foreach(self::$accounts->search(array( + 'type' => 'groups', + 'start' => false, + 'order' => 'account_lid', + 'sort' => 'ASC', + )) as $account_id => $data) + { + $sel_options['filter'][$data['account_id']] = empty($data['account_description']) ? $data['account_lid'] : array( + 'label' => $data['account_lid'], + 'title' => $data['account_description'], + ); + } + $sel_options['account_primary_group'] = $sel_options['filter']; + unset($sel_options['account_primary_group']['']); + $tpl->exec('admin.admin_ui.index', $content, $sel_options); } + /** + * Actions on users + * + * @return array + */ + public static function user_actions() + { + $actions = array( + 'edit' => array( + 'caption' => 'Open', + 'default' => true, + 'allowOnMultiple' => false, + 'url' => 'menuaction=admin.uiaccounts.edit_user&account_id=$id', + 'group' => $group=0, + 'onExecute' => 'javaScript:app.admin.iframe_location', + ), + 'view' => array( + 'caption' => 'View', + 'allowOnMultiple' => false, + 'url' => 'menuaction=admin.uiaccounts.view_user&account_id=$id', + 'group' => $group, + 'onExecute' => 'javaScript:app.admin.iframe_location', + ), + ); + ++$group; + // supporting both old way using $GLOBALS['menuData'] and new just returning data in hook + $apps = array_unique(array_merge(array('admin'), $GLOBALS['egw']->hooks->hook_implemented('edit_user'))); + foreach($apps as $n => $app) + { +if ($app == 'felamimail') continue; // disabled fmail for now, as it break whole admin, dono why + $GLOBALS['menuData'] = $data = array(); + $data = $GLOBALS['egw']->hooks->single('edit_user', $app, true); + if (!$data) $data = $GLOBALS['menuData']; + foreach($data as $item) + { + // allow hook to return "real" actions, but still support legacy: description, url, extradata, options + if (empty($item['caption'])) + { + $item['caption'] = $item['description']; + unset($item[$description]); + } + if (isset($item['url']) && isset($item['extradata'])) + { + $item['url'] = $item['extradata'].'&account_id=$id'; + $item['id'] = substr($item['extradata'], 11); + unset($item['extradata']); + if ($item['options'] && preg_match('/(egw_openWindowCentered2?|window.open)\([^)]+,(\d+),(\d+).*(title="([^"]+)")?/', $item['options'], $matches)) + { + $item['popup'] = $matches[2].'x'.$matches[3]; + $item['onExecute'] = 'javaScript:nm_action'; + if (isset($matches[5])) $item['tooltip'] = $matches[5]; + unset($item['options']); + } + } + if (empty($item['icon'])) $item['icon'] = $app.'/navbar'; + if (empty($item['group'])) $item['group'] = $group; + if (empty($item['onExecute'])) $item['onExecute'] = 'javaScript:app.admin.iframe_location'; + + $actions[$item['id']] = $item; + } + } + $actions['delete'] = array( + 'caption' => 'Delete', + 'group' => ++$group, + 'url' => 'menuaction=admin.uiaccounts.delete_user&account_id=$id', + 'onExecute' => 'javaScript:app.admin.iframe_location', + ); + //error_log(__METHOD__."() actions=".array2string($actions)); + return $actions; + } + + /** + * Callback for nextmatch to fetch users + * + * @param array $query + * @param array &$rows=null + * @return int total number of rows available + */ + public static function get_users(array $query, array &$rows=null) + { + $params = array( + 'type' => (int)$query['filter'] ? (int)$query['filter'] : 'accounts', + 'start' => $query['start'], + 'offset' => $query['num_rows'], + 'order' => $query['order'], + 'sort' => $query['sort'], + 'active' => false, + ); + if ($query['searchletter']) + { + $params['query'] = $query['searchletter']; + $params['query_type'] = 'start'; + } + elseif($query['search']) + { + $params['query'] = $query['search']; + $params['query_type'] = 'all'; + } + + $rows = self::$accounts->search($params); + error_log(__METHOD__."() accounts->search(".array2string($params).") total=".self::$accounts->total); + + foreach($rows as &$row) + { + $row['status'] = self::$accounts->is_expired($row) ? + lang('Expired').' '.egw_time::to($row['account_expires'], true) : + (!self::$accounts->is_active($row) ? lang('Disabled') : + ($row['account_expires'] != -1 ? lang('Expires').' '.egw_time::to($row['account_expires'], true) : + lang('Enabled'))); + + if (!self::$accounts->is_active($row)) $row['status_class'] = 'adminAccountInactive'; + } + + return self::$accounts->total; + } + /** * Autoload tree from $_GET['id'] on */ @@ -144,6 +296,8 @@ class admin_ui { foreach($GLOBALS['egw']->accounts->search(array( 'type' => 'groups', + 'order' => 'account_lid', + 'sort' => 'ASC', )) as $group) { $tree['item'][] = self::fix_userdata(array( @@ -183,7 +337,12 @@ class admin_ui return $data; } - private static function strip_item_keys(&$items) + /** + * Attribute 'item' has to be an array + * + * @param array $items + */ + private static function strip_item_keys(array &$items) { $items = array_values($items); foreach($items as &$item) @@ -211,4 +370,13 @@ class admin_ui } return array_merge($GLOBALS['egw']->hooks->process('admin', array('admin')), self::$hook_data); } + + /** + * Init static variables + */ + public static function init_static() + { + self::$accounts = $GLOBALS['egw']->accounts; + } } +admin_ui::init_static(); diff --git a/admin/js/app.js b/admin/js/app.js index 30bb8d6ff8..3fb598db13 100644 --- a/admin/js/app.js +++ b/admin/js/app.js @@ -21,6 +21,15 @@ app.admin = AppJS.extend( * et2 widget container */ et2: null, + /** + * reference to splitter + */ + splitter: null, + + /** + * reference to splitter + */ + iframe: null, /** * Constructor @@ -57,8 +66,30 @@ app.admin = AppJS.extend( this.et2 = _et2.widgetContainer; - var iframe = this.et2.getWidgetById('admin_iframe'); + var iframe = this.iframe = this.et2.getWidgetById('admin_iframe'); if (iframe) iframe.set_src(egw.webserverUrl+'/admin/index.php'); + + var splitter = this.splitter = this.et2.getWidgetById('admin_splitter'); + if (splitter) + { + window.setTimeout(function(){ + splitter.dock(); + }, 1); + } + }, + + /** + * Set location of iframe for given _action and _sender (row) + * + * @param _action + * @param _senders + */ + iframe_location: function(_action, _senders) + { + var id = _senders[0].id.split('::'); + var url = _action.data.url.replace(/(%24|\$)id/, id[1]); + + this.iframe.set_src(url); }, /** @@ -70,15 +101,21 @@ app.admin = AppJS.extend( run: function(_id, _widget) { var link = _widget.getUserData(_id, 'link'); - var iframe = this.et2.getWidgetById('admin_iframe'); - if (typeof link == 'undefined') + if (_id == '/accounts' || _id.substr(0, 8) == '/groups/') + { + this.splitter.undock(); + var parts = _id.split('/'); + this.et2.getWidgetById('admin_nm').applyFilters({ filter: parts[2] ? parts[2] : '', search: ''}); + } + else if (typeof link == 'undefined') { _widget.openItem(_id, 'toggle'); } else if (link[0] == '/' || link.substr(0,4) == 'http') { - iframe.set_src(link+'&nonavbar=1'); + this.splitter.dock(); + this.iframe.set_src(link+'&nonavbar=1'); } else if (link.substr(0,11) == 'javascript:') { diff --git a/admin/lang/egw_de.lang b/admin/lang/egw_de.lang index f8fb957c43..8a48235679 100644 --- a/admin/lang/egw_de.lang +++ b/admin/lang/egw_de.lang @@ -282,7 +282,8 @@ error setting timer, wrong syntax or maybe there's one already running !!! admin error! no appname found admin de Fehler: Kein Anwendungsname gefunden error: %1 not found or other error !!! admin de Fehler: %1 nicht gefunden oder anderer Fehler! exists admin de existiert -expires admin de abgelaufen +expired admin de abgelaufen +expires admin de läuft ab explanation of ldapman admin de Dieses Modul ist derzeit nur für folgende Konfiguration getestet: Postfix, LDAP, Courier-Imap, Procmail und erfordert die Schemas: core und qmail(OID 7914). Weitere Konfigurationshinweise sind im README.ldapman im DOC Verzeichnis des Moduls ADMIN zu finden. exports groups into a csv file. admin de Benutzergruppen in eine CSV-Datei exportieren. exports users into a csv file. admin de Benutzer in eine CSV-Datei exportieren. diff --git a/admin/lang/egw_en.lang b/admin/lang/egw_en.lang index f51c41b0f0..0a7788329d 100644 --- a/admin/lang/egw_en.lang +++ b/admin/lang/egw_en.lang @@ -283,6 +283,7 @@ error setting timer, wrong syntax or maybe there's one already running !!! admin error! no appname found admin en Error: No app name found! error: %1 not found or other error !!! admin en Error: %1 not found or other error! exists admin en Exists +expired admin en Expired expires admin en Expires explanation of ldapman admin en This module has been tested so far for POSTFIX, LDAP, Courier-IMAP and need the schemas CORE and QMAIL (OID7914). More details about using and configuring this system can be found in README.ldapman in the doc folder of ADMIN. exports groups into a csv file. admin en Exports groups into a CSV file. diff --git a/admin/templates/default/app.css b/admin/templates/default/app.css index 4e260dde07..2ae19bae06 100644 --- a/admin/templates/default/app.css +++ b/admin/templates/default/app.css @@ -19,3 +19,20 @@ div#divAppbox { body { background-image: none; } + +/* otherwise it is transparent */ +#admin_iframe { + background-color: white; +} + +tr.adminAccountInactive .adminStatus { + color: red; +} + +.adminOverflowEllipsis { + width: 100%; + white-space: nowrap; + display: block; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/admin/templates/default/index.xet b/admin/templates/default/index.xet index a17e93ec95..b420461f55 100644 --- a/admin/templates/default/index.xet +++ b/admin/templates/default/index.xet @@ -1,9 +1,53 @@ -