Add support for filtering records to be exported.

Filterable fields are attempted to be autodetected by using the exportable fields.
Records can be filtered by fields with type select,select-cat,select-account,date,date-time (according to egw_record class) 
only at this time.  Filters are saved in the definition and used with scheduled exports.  They are also available to the
user for modification in the export dialog.
This commit is contained in:
Nathan Gray 2012-12-31 20:36:28 +00:00
parent 841d3b67bd
commit 0a91bc5aa9
15 changed files with 743 additions and 15 deletions

View File

@ -0,0 +1,257 @@
<?php
/**
* Widget for setting filters
*
* @author Nathan Gray
* @version $Id$
*/
/**
* Extend custom fields and make an general advanced filter
*
* Much of this is copied from customfields_widget and adapted.
* We assume that the app can handle pretty much any field => value combination
* we send via col_filter, but the plugin gets a chance to interpret the filter
* settings.
*
* Selectboxes are easy, we just turn them into multi-selects.
*
* For dates we either use a relative date selection, or a literal date selection.
* Relative date options are in importexport_helper_functions::$relative_dates
*
* Most text fields are ignored.
*/
class filter_widget extends customfields_widget
{
public $prefix = '';
public $human_name = array(
'filter' => 'Import|Export filter'
);
public function __construct($ui, $appname = null)
{
$this->advanced_search = true;
parent::__construct($ui, $appname);
}
/**
* pre-processing of the extension
*
* This function is called before the extension gets rendered
*
* @param string $form_name form-name of the control
* @param mixed &$value value / existing content, can be modified
* @param array &$cell array with the widget, can be modified for ui-independent widgets
* @param array &$readonlys names of widgets as key, to be made readonly
* @param mixed &$extension_data data the extension can store persisten between pre- and post-process
* @param etemplate &$tmpl reference to the template we belong too
* @return boolean true if extra label is allowed, false otherwise
*/
public function pre_process($form_name,&$value,&$cell,&$readonlys,&$extension_data,$tmpl)
{
$fields = $value['fields'];
unset($value['fields']);
list($relative_dates) = explode(',',$cell['size']);
if($cell['relative_dates']) $relative_dates = true;
// Fallback, so there's something there...
if(!is_array($fields))
{
$cell['type'] = 'label';
$cell['label'] = 'No fields';
return True;
}
// making the cell an empty grid
$cell['type'] = 'grid';
$cell['data'] = array(array());
$cell['rows'] = $cell['cols'] = 0;
$cell['size'] = '';
$n = 1;
foreach($fields as $lname => $field)
{
$new_row = null; boetemplate::add_child($cell,$new_row);
$row_class = 'row';
boetemplate::add_child($cell,$label =& boetemplate::empty_cell('label','',array(
'label' => $field['label'],
'no_lang' => substr(lang($field['label']),-1) == '*' ? 2 : 0,
'span' => $field['type'] === 'label' ? '2' : '',
)));
switch($field['type'])
{
case 'date':
case 'date-time':
// Need a range here
$options = '';
if($relative_dates)
{
$input = self::do_relative_date($lname, $value, $options, $readonly);
}
else
{
$input = self::do_absolute_date($lname, $value, $options, $readonly);
}
break;
case 'ajax_select' :
// Set some reasonable defaults for the widget
$options = array(
'get_title' => 'etemplate.ajax_select_widget.array_title',
'get_rows' => 'etemplate.ajax_select_widget.array_rows',
'id_field' => ajax_select_widget::ARRAY_KEY,
);
if($field['rows']) {
$options['num_rows'] = $field['rows'];
}
// If you specify an option known to the AJAX Select widget, it will be pulled from the list of values
// and used as such. All unknown values will be used for selection, not passed through to the query
if (isset($field['values']['@']))
{
$options['values'] = $this->_get_options_from_file($field['values']['@']);
unset($field['values']['@']);
} else {
$options['values'] = array_diff_key($field['values'], array_flip(ajax_select_widget::$known_options));
}
$options = array_merge($options, array_intersect_key($field['values'], array_flip(ajax_select_widget::$known_options)));
$input = boetemplate::empty_cell('ajax_select', $lname, array(
'readonly' => $readonly,
'no_lang' => True,
'size' => $options
));
break;
case 'link-entry':
$input =& boetemplate::empty_cell('link-entry',$this->prefix.$lname,array(
'size' => $field['type'] == 'link-entry' ? '' : $field['type'],
));
// register post-processing of link widget to get eg. needed/required validation
etemplate_old::$request->set_to_process(etemplate_old::form_name($form_name,$this->prefix.$lname), 'ext-link');
break;
case 'select':
default:
if(strpos($field['type'],'select') === 0)
{
if (count($field['values']) == 1 && isset($field['values']['@']))
{
$field['values'] = $this->_get_options_from_file($field['values']['@']);
}
foreach((array)$field['values'] as $key => $val)
{
if (substr($val = lang($val),-1) != '*')
{
$field['values'][$key] = $val;
}
}
$input =& boetemplate::empty_cell($field['type'],$lname,array(
'sel_options' => $field['values'],
'size' => $field['rows'],
'enhance' => true,
'no_lang' => True,
));
}
elseif (in_array($field['type'], array_keys(egw_link::app_list())))
{
// Link entry to a specific app
$input =& boetemplate::empty_cell('link-entry',$lname,array(
'size' => $field['type'] == 'link-entry' ? '' : $field['type'],
));
// register post-processing of link widget to get eg. needed/required validation
etemplate_old::$request->set_to_process(etemplate_old::form_name($form_name,$lname), 'ext-link');
} else {
error_log('Trying to filter with unsupported field type: ' . $field['type']);
$input =& boetemplate::empty_cell($field['type'],$lname,array(
'sel_options' => $field['values'],
'size' => $field['rows'],
'no_lang' => True,
));
}
}
$cell['data'][0]['c'.$n++] = $row_class.',top';
if (!is_null($input))
{
if ($readonly) $input['readonly'] = true;
$input['needed'] = $cell['needed'] || $field['needed'];
if (!empty($field['help']) && $row_class != 'th')
{
$input['help'] = $field['help'];
$input['no_lang'] = substr(lang($help),-1) == '*' ? 2 : 0;
}
boetemplate::add_child($cell,$input);
unset($input);
}
unset($label);
}
return false;
}
/**
* Create widgets to select a relative date range
*
* @param $lname Field name
* @param $options
* @param $readonly
*
* @return Array of widget info
*/
protected static function do_relative_date($lname, Array &$value, $options, $readonly)
{
// Maybe this could be moved to date widget
$input = boetemplate::empty_cell('select',$lname, array(
'readonly' => $readonly,
'no_lang' => true,
'options' => $options,
'sel_options' => array('' => lang('all'))
));
foreach(importexport_helper_functions::$relative_dates as $label => $values)
{
$input['sel_options'][$label] = lang($label);
}
return $input;
}
/**
* Create widgets to select an absolute date range
*
* @param $lname Field name
* @param $options
* @param $readonly
*
* @return Array of widget info
*/
protected static function do_absolute_date($lname, Array &$value, $options, $readonly)
{
$input = boetemplate::empty_cell('hbox',$lname);
$type = 'date';
$from = boetemplate::empty_cell($type, $lname.'[from]',array(
'readonly' => $readonly,
'no_lang' => True,
'size' => $options
));
$to = boetemplate::empty_cell($type, $lname.'[to]', array(
'readonly' => $readonly,
'no_lang' => True,
'size' => $options
));
boetemplate::add_child($input, $from);
boetemplate::add_child($input,boetemplate::empty_cell('label','',array(
'label' => lang('to'),
'no_lang' => true
)));
boetemplate::add_child($input, $to);
return $input;
}
}

View File

@ -31,6 +31,7 @@ class importexport_definition implements importexport_iface_egw_record {
'type' => 'string',
'allowed_users' => 'array',
'plugin_options' => 'array',
'filter' => 'array',
'owner' => 'int',
'description' => 'string',
'modified' => 'timestamp'
@ -79,6 +80,8 @@ class importexport_definition implements importexport_iface_egw_record {
}
$options_data = importexport_arrayxml::xml2array( $this->definition['plugin_options'] );
$this->definition['plugin_options'] = $options_data['root'];
if($this->definition['filter']) $filter = importexport_arrayxml::xml2array( $this->definition['filter'] );
$this->definition['filter'] = $filter['root'];
}
}
@ -110,6 +113,8 @@ class importexport_definition implements importexport_iface_egw_record {
return $this->get_allowed_users();
case 'plugin_options' :
return $this->get_options();
case 'filter':
return $this->get_filter();
default :
return $this->definition[$_attribute_name];
}
@ -124,6 +129,8 @@ class importexport_definition implements importexport_iface_egw_record {
return $this->set_allowed_users($_data);
case 'plugin_options' :
return $this->set_options($_data);
case 'filter':
return $this->set_filter($_data);
default :
$this->definition[$_attribute_name] = $_data;
return;
@ -166,6 +173,24 @@ class importexport_definition implements importexport_iface_egw_record {
$this->definition['plugin_options'] = $_plugin_options;
}
/**
* Get stored data filter
*
* @return array
*/
private function get_filter() {
return $this->definition['filter'];
}
/**
* Set stored data filter
*
* @param filter array of field => settings
*/
private function set_filter(Array $filter) {
$this->definition['filter'] = $filter;
}
/**
* converts this object to array.
* @abstract We need such a function cause PHP5
@ -178,6 +203,7 @@ class importexport_definition implements importexport_iface_egw_record {
$definition = $this->definition;
$definition['allowed_users'] = $this->get_allowed_users();
$definition['plugin_options'] = $this->get_options();
$definition['filter'] = $this->get_filter();
return $definition;
}
@ -211,6 +237,7 @@ class importexport_definition implements importexport_iface_egw_record {
// convert plugin_options into internal representation
$this->set_allowed_users( $this->definition['allowed_users'] );
$this->set_options( $this->definition['plugin_options'] ? $this->definition['plugin_options'] : array());
$this->set_filter( $this->definition['filter'] ? $this->definition['filter'] : array());
}
/**
@ -235,6 +262,7 @@ class importexport_definition implements importexport_iface_egw_record {
$this->so_sql->data = $this->definition;
$this->so_sql->data['plugin_options'] = importexport_arrayxml::array2xml( $this->definition['plugin_options'] );
$this->so_sql->data['filter'] = importexport_arrayxml::array2xml( $this->definition['filter'] );
$this->so_sql->data['modified'] = time();
if ($this->so_sql->save( array( 'definition_id' => $_dst_identifier ))) {
throw new Exception('Error: so_sql was not able to save definition: '.$this->get_identifier());

View File

@ -612,6 +612,7 @@ class importexport_definitions_ui
{
$this->response = new xajaxResponse();
egw_framework::include_css_js_response();
if ($content['closewindow'])
{
$this->response->addScript("opener.location.reload();");
@ -639,6 +640,7 @@ class importexport_definitions_ui
{
$GLOBALS['egw']->js->set_onload("document.getElementById('picturebox').style.display = 'none';");
egw_framework::validate_file('.', 'etemplate', 'etemplate');
egw_framework::validate_file('.', 'etemplate', 'etemplate');
common::egw_header();
echo '<div id="divMain">'."\n";
echo '<div><h3>{Im|Ex}port Wizard</h3></div>';

View File

@ -173,6 +173,24 @@ class importexport_export_ui {
$content['plugin_options_template'] = $options;
}
}
$content['filter'] = $definition->filter;
$content['filter']['fields'] = importexport_helper_functions::get_filter_fields($_appname, $selected_plugin);
if(!$content['filter']['fields'])
{
$this->js->set_onload("\$j('input[value=\"filter\"]').parent().hide();");
$content['no_filter'] = true;
}
else
{
// Process relative dates into the current absolute date
foreach($content['filter']['fields'] as $field => $settings)
{
if($content['filter'][$field] && strpos($settings['type'],'date') === 0)
{
$content['filter'][$field] = importexport_helper_functions::date_rel2abs($content['filter'][$field]);
}
}
}
}
// fill selection tab
@ -209,9 +227,18 @@ class importexport_export_ui {
disable_button('exec[export]');
");
}
// Disable / hide definition filter if not selected
if($content['selection'] !== 'filter')
{
$this->js->set_onload("
\$j('div.filters').hide();
");
}
$preserv['old_definition'] = $content['definition'];
if (($prefs = $GLOBALS['egw_info']['user']['preferences']['importexport'][$definition->definition_id]) &&
($prefs = unserialize($prefs)) && !$content['selection']['plugin_override'])
($prefs = unserialize($prefs)) && is_array($content['selection']) && !$content['selection']['plugin_override'])
{
$selection = $content['selection'];
$content = array_merge_recursive($content,$prefs);
@ -260,6 +287,26 @@ class importexport_export_ui {
'mapping' => array()
);
}
// Set filter
// Note that because not all dates are DB dates, the plugin has to handle them
$filter = $definition->filter;
foreach($_content['filter'] as $key => $value)
{
// Handle multiple values
if(!is_array($value) && strpos($value,',') !== false) $value = explode(',',$value);
$filter[$key] = $value;
// Skip empty values or empty ranges
if(!$value || is_array($value) && array_key_exists('from',$value) && !$value['from'] && !$value['to'] )
{
unset($filter[$key]);
}
}
unset($_content['filter']);
$definition->filter = $filter;
$definition->plugin_options = array_merge(
$definition->plugin_options,
$_content

View File

@ -26,6 +26,25 @@ class importexport_helper_functions {
*/
public static $dry_run = false;
/**
* Relative date ranges for filtering
*/
public static $relative_dates = array( // Start: year,month,day,week, End: year,month,day,week
'Today' => array(0,0,0,0, 0,0,1,0),
'Yesterday' => array(0,0,-1,0, 0,0,0,0),
'This week' => array(0,0,0,0, 0,0,0,1),
'Last week' => array(0,0,0,-1, 0,0,0,0),
'This month' => array(0,0,0,0, 0,1,0,0),
'Last month' => array(0,-1,0,0, 0,0,0,0),
'Last 3 months' => array(0,-3,0,0, 0,1,0,0),
'This quarter'=> array(0,0,0,0, 0,0,0,0), // Just a marker, needs special handling
'Last quarter'=> array(0,-4,0,0, 0,-4,0,0), // Just a marker
'This year' => array(0,0,0,0, 1,0,0,0),
'Last year' => array(-1,0,0,0, 0,0,0,0),
'2 years ago' => array(-2,0,0,0, -1,0,0,0),
'3 years ago' => array(-3,0,0,0, -2,0,0,0),
);
/**
* Files known to cause problems, and will be skipped in a plugin scan
* If you put appname => true, the whole app will be skipped.
@ -515,4 +534,181 @@ class importexport_helper_functions {
}
return $list;
}
/**
* Get a list of filterable fields, and options for those fields
*
* It tries to automatically pull filterable fields from the list of fields in the wizard,
* and sets widget properties. The plugin can edit / set the fields by implementing
* get_filter_fields(Array &$fields).
*
* Currently only supports select,select-cat,select-account,date,date-time
*
* @param $app_name String name of app
* @param $plugin_name Name of the plugin
*
* @return Array ([fieldname] => array(widget settings), ...)
*/
public static function get_filter_fields($app_name, $plugin_name, $wizard_plugin = null, $record_classname = null)
{
$fields = array();
try {
if($record_classname == null) $record_classname = $app_name . '_egw_record';
if(!class_exists($record_classname)) throw new Exception('Bad class name ' . $record_classname);
$plugin = is_object($plugin_name) ? $plugin_name : new $plugin_name();
$plugin_name = get_class($plugin);
if(!$wizard_plugin)
{
$wizard_name = $app_name . '_wizard_' . str_replace($app_name . '_', '', $plugin_name);
if(!class_exists($wizard_name)) throw new Exception('Bad wizard name ' . $wizard_name);
$wizard_plugin = new $wizard_name;
}
}
catch (Exception $e)
{
error_log($e->getMessage());
return array();
}
// Get field -> label map and initialize fields using wizard field order
$fields = $export_fields = $wizard_plugin->get_export_fields();
foreach($record_classname::$types as $type => $type_fields)
{
// Only these for now, until filter methods for others are figured out
if(!in_array($type, array('select','select-cat','select-account','date','date-time'))) continue;
foreach($type_fields as $field_name)
{
$fields[$field_name] = array(
'name' => $field_name,
'label' => $export_fields[$field_name] ? $export_fields[$field_name] : $field_name,
'type' => $type
);
}
}
// Add custom fields
$custom = config::get_customfields($app_name);
foreach($custom as $field_name => $settings)
{
$settings['name'] = '#'.$field_name;
$fields['#'.$field_name] = $settings;
}
foreach($fields as $field_name => &$settings) {
// Can't really filter on these (or at least no generic, sane way figured out yet)
if(!is_array($settings) || in_array($settings['type'], array('text','button', 'label','url','url-email','url-phone','htmlarea')))
{
unset($fields[$field_name]);
continue;
}
if($settings['type'] == 'radio') $settings['type'] = 'select';
switch($settings['type'])
{
case 'checkbox':
// This isn't quite right - there's only 2 options and you can select both
$settings['type'] = 'select-bool';
$settings['rows'] = 1;
$settings['enhance'] = true;
break;
case 'select-cat':
$settings['rows'] = "5,,,$app_name";
$settings['enhance'] = true;
break;
case 'select-account':
$settings['rows'] = '5,both';
$settings['enhance'] = true;
break;
case 'select':
$settings['rows'] = 5;
$settings['enhance'] = true;
break;
}
}
if(method_exists($plugin, 'get_filter_fields'))
{
$plugin->get_filter_fields($fields);
}
return $fields;
}
/**
* Parse a relative date (Yesterday) into absolute (2012-12-31) date
*
* @param $value String description of date matching $relative_dates
*
* @return Array([from] => timestamp, [to]=> timestamp), inclusive
*/
public static function date_rel2abs($value)
{
if(is_array($value))
{
$abs = array();
foreach($value as $key => $val)
{
$abs[$key] = self::date_rel2abs($val);
}
return $abs;
}
if($date = self::$relative_dates[$value])
{
$year = (int) date('Y');
$month = (int) date('m');
$day = (int) date('d');
$today = mktime(0,0,0,date('m'),date('d'),date('Y'));
list($syear,$smonth,$sday,$sweek,$eyear,$emonth,$eday,$eweek) = $date;
if(stripos($value, 'quarter') !== false)
{
// Handle quarters
$start = mktime(0,0,0,((int)floor(($smonth+$month) / 3.1)) * 3 + 1, 1, $year);
$end = mktime(0,0,0,((int)floor(($emonth+$month) / 3.1)+1) * 3 + 1, 1, $year);
}
elseif ($syear || $eyear)
{
$start = mktime(0,0,0,1,1,$syear+$year);
$end = mktime(0,0,0,1,1,$eyear+$year);
}
elseif ($smonth || $emonth)
{
$start = mktime(0,0,0,$smonth+$month,1,$year);
$end = mktime(0,0,0,$emonth+$month,1,$year);
}
elseif ($sday || $eday)
{
$start = mktime(0,0,0,$month,$sday+$day,$year);
$end = mktime(0,0,0,$month,$eday+$day,$year);
}
elseif ($sweek || $eweek)
{
$wday = (int) date('w'); // 0=sun, ..., 6=sat
switch($GLOBALS['egw_info']['user']['preferences']['calendar']['weekdaystarts'])
{
case 'Sunday':
$weekstart = $today - $wday * 24*60*60;
break;
case 'Saturday':
$weekstart = $today - (6-$wday) * 24*60*60;
break;
case 'Moday':
default:
$weekstart = $today - ($wday ? $wday-1 : 6) * 24*60*60;
break;
}
$start = $weekstart + $sweek*7*24*60*60;
$end = $weekstart + $eweek*7*24*60*60;
}
$end_param = $end - 24*60*60;
// Take 1 second off end to provide an inclusive range.for filtering
$end -= 1;
//echo __METHOD__."($value,$start,$end) today=".date('l, Y-m-d H:i',$today)." ==> <br />".date('l, Y-m-d H:i:s',$start)." <= date <= ".date('l, Y-m-d H:i:s',$end)."</p>\n";
return array('from' => $start, 'to' => $end);
}
return null;
}
} // end of importexport_helper_functions

View File

@ -460,8 +460,30 @@
if($type == 'export')
{
// Set to export all
$definition->plugin_options = array_merge($definition->plugin_options, array('selection' => 'all'));
// Set to export all or filter, if set
$selection = array('selection' => 'all');
if($definition->filter)
{
$fields = importexport_helper_functions::get_filter_fields($definition->application, $po);
$selection = array('selection' => 'filter');
$filters = array();
foreach($definition->filter as $field => $value)
{
// Handle multiple values
if(!is_array($value) && strpos($value,',') !== false) $value = explode(',',$value);
$filters[$field] = $value;
// Process relative dates into the current absolute date
if($filters[$field] && strpos($fields[$field]['type'],'date') === 0)
{
$filters[$field] = importexport_helper_functions::date_rel2abs($value);
}
}
// Update filter to use current absolute dates
$definition->filter = $filters;
}
$definition->plugin_options = array_merge($definition->plugin_options, $selection);
}
foreach($targets as $target)

View File

@ -31,6 +31,7 @@ class importexport_wizard_basic_export_csv
protected $step_templates = array(
'wizard_step30' => 'importexport.wizard_basic_export_csv.choose_fields',
'wizard_step40' => 'importexport.wizard_basic_export_csv.choosesepncharset',
'wizard_step50' => 'importexport.wizard_basic_export_csv.filter',
);
@ -58,6 +59,7 @@ class importexport_wizard_basic_export_csv
$this->steps = array(
'wizard_step30' => lang('Choose fields to export'),
'wizard_step40' => lang('Choose seperator and charset'),
'wizard_step50' => lang('Filters'),
);
list($appname, $part2) = explode('_', get_class($this));
if(!$GLOBALS['egw_info']['apps'][$appname]) $appname .= '_'.$part2; // Handle apps with _ in the name
@ -222,6 +224,73 @@ class importexport_wizard_basic_export_csv
}
/**
* Set export filters
*
* @param array $content
* @param array $sel_options
* @param array $readonlys
* @param array $preserv
* @return string template name
*/
function wizard_step50(&$content, &$sel_options, &$readonlys, &$preserv)
{
if($this->debug) error_log(get_class($this) . '::' . __METHOD__ .'->$content '.print_r($content,true));
// return from submit
if ($content['step'] == 'wizard_step50') {
// Process submitted
unset($content['filter']);
unset($content['set_filter']['fields']);
foreach($content['set_filter'] as $key => $value)
{
if($value) {
$content['filter'][$key] = $value;
}
}
unset($content['set_filter']);
// Next step
switch (array_search('pressed', $content['button']))
{
case 'next':
return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],1);
case 'previous' :
return $GLOBALS['egw']->importexport_definitions_ui->get_step($content['step'],-1);
case 'finish':
return 'wizard_finish';
default :
return $this->wizard_step50($content,$sel_options,$readonlys,$preserv);
}
} else {
// Step 50 - filters
$content['msg'] = $this->steps['wizard_step50'];
$content['step'] = 'wizard_step50';
// Find filterable fields
if(!$content['set_filter'] && $content['filter']) {
$load = true;
}
$content['set_filter']['fields'] = importexport_helper_functions::get_filter_fields(
$content['application'],$content['plugin'],$this
);
// Load existing filter from either content or definition
if($load)
{
foreach($content['set_filter']['fields'] as $field => $settings)
{
$content['set_filter'][$field] = $content['filter'][$field];
}
}
$sel_options = array();
$preserv = $content;
unset ($preserv['button']);
return $this->step_templates[$content['step']];
}
}
/**
* Expose export fields for use elsewhere
*/

View File

@ -10,5 +10,8 @@ function clear_options(id) {
for(var count = list.options.length - 1; count >= 0; count--) {
list.options[count] = null;
}
if($j().chosen && list) {
$j(list).trigger("liszt:updated");
}
}

View File

@ -2,7 +2,7 @@
/**
* EGroupware - eTemplates for Application importexport
* http://www.egroupware.org
* generated by soetemplate::dump4setup() 2012-12-17 16:23
* generated by soetemplate::dump4setup() 2012-12-31 13:19
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package importexport
@ -89,7 +89,14 @@ $templ_data[] = array('name' => 'importexport.export_dialog.options_tab','templa
display: none;
}','modified' => '1286482130',);
$templ_data[] = array('name' => 'importexport.export_dialog.selection_tab','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:2:{s:2:"c1";s:4:",top";s:2:"h1";s:27:",@plugin_selectors_template";}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:4:"html";s:4:"name";s:21:"plugin_selectors_html";s:7:"no_lang";s:1:"1";}}i:2;a:1:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"name";s:26:"@plugin_selectors_template";}}}s:4:"rows";i:2;s:4:"cols";i:1;s:4:"size";s:6:",200px";s:7:"options";a:1:{i:1;s:5:"200px";}}}','size' => ',200px','style' => '','modified' => '1158223796',);
$templ_data[] = array('name' => 'importexport.export_dialog.selection_tab','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:5:{i:0;a:10:{s:2:"h3";s:30:"20,!@plugin_selectors_template";s:2:"h2";s:27:",@plugin_selectors_template";s:2:"c2";s:4:",top";s:2:"h4";s:28:",!@plugin_selectors_template";s:2:"c3";s:2:"th";s:2:"h1";s:29:"20,@plugin_selectors_template";s:2:"c1";s:2:"th";s:2:"c4";s:4:",top";s:1:"B";s:14:"300,@no_filter";s:1:"A";s:3:"150";}i:1;a:2:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Definition filter";}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:4:"html";s:4:"name";s:21:"plugin_selectors_html";s:7:"no_lang";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:3:"box";s:4:"span";s:8:",filters";s:4:"size";s:1:"1";i:1;a:2:{s:4:"type";s:6:"filter";s:4:"name";s:6:"filter";}}}i:3;a:2:{s:1:"A";a:1:{s:4:"type";s:5:"label";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Definition filter";}}i:4;a:2:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"name";s:26:"@plugin_selectors_template";}s:1:"B";a:5:{s:4:"type";s:3:"box";s:4:"span";s:8:",filters";s:4:"size";s:1:"1";i:1;a:2:{s:4:"type";s:6:"filter";s:4:"name";s:6:"filter";}s:7:"onclick";s:105:"\\$j(\'input[value=\\\'filter\\\']\').not(\':checked\').attr(\'checked\',true).parent().effect(\'highlight\',{},2000);";}}}s:4:"rows";i:4;s:4:"cols";i:2;s:4:"size";s:10:"100%,200px";s:7:"options";a:2:{i:0;s:4:"100%";i:1;s:5:"200px";}}}','size' => '100%,200px','style' => 'select[multiple] {
width: 400px;
}
.filters {
max-height: 300px;
min-height: 150px;
overflow-y: auto;
}','modified' => '1158223796',);
$templ_data[] = array('name' => 'importexport.import_definition','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:92:"Import definitions (Attension: Existing definitions with equal names will be overwritten!!!)";}}i:2;a:1:{s:1:"A";a:2:{s:4:"type";s:4:"file";s:4:"name";s:11:"import_file";}}i:3;a:1:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:6:"Import";s:4:"name";s:6:"import";}i:2;a:3:{s:4:"type";s:6:"button";s:4:"name";s:6:"update";s:5:"label";s:26:"Update default-definitions";}}}}s:4:"rows";i:3;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1306253183',);
@ -122,6 +129,10 @@ $templ_data[] = array('name' => 'importexport.wizard_basic_export_csv.choosesepn
$templ_data[] = array('name' => 'importexport.wizard_basic_export_csv.choose_fields','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"span";s:3:"all";s:4:"name";s:3:"msg";}}i:2;a:1:{s:1:"A";a:7:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:1:{s:2:"c1";s:2:"th";}i:1;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Field";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Export";}i:2;a:7:{s:4:"type";s:10:"buttononly";s:4:"size";s:5:"check";s:5:"label";s:9:"Check all";s:4:"name";s:9:"check_all";s:4:"help";s:9:"Check all";s:7:"onclick";s:98:"jQuery(\'input:checkbox\').attr(\'checked\', !jQuery(\'input:checkbox\').attr(\'checked\')); return false;";s:6:"needed";s:1:"1";}}}i:2;a:2:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:4:"name";s:12:"${row}[name]";s:7:"no_lang";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:8:"checkbox";s:7:"no_lang";s:1:"1";s:4:"name";s:14:"export[${row}]";s:4:"size";s:18:"{$row_cont[field]}";}}}s:4:"rows";i:2;s:4:"cols";i:2;s:4:"size";s:10:",,,,,,auto";s:4:"name";s:6:"fields";s:7:"options";a:1:{i:6;s:4:"auto";}}}}s:4:"rows";i:2;s:4:"cols";i:1;s:7:"options";a:0:{}}}','size' => '','style' => '','modified' => '1286466690',);
$templ_data[] = array('name' => 'importexport.wizard_basic_export_csv.filter','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:6:"filter";s:4:"name";s:10:"set_filter";s:4:"size";s:1:"1";}}}s:4:"rows";i:1;s:4:"cols";i:1;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => 'select {
width: 200px;
}','modified' => '1356969972',);
$templ_data[] = array('name' => 'importexport.wizard_basic_import_csv.choosesepncharset','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:7:{i:0;a:2:{s:1:"B";s:5:"180px";s:2:"h5";s:9:",@no_cats";}i:1;a:2:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:7:"no_lang";s:1:"1";s:4:"name";s:3:"msg";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:14:"Fieldseperator";}s:1:"B";a:4:{s:4:"type";s:4:"text";s:7:"no_lang";s:1:"1";s:4:"name";s:8:"fieldsep";s:4:"size";s:1:"1";}}i:3;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:15:"Charset of file";}s:1:"B";a:4:{s:4:"type";s:6:"select";s:7:"no_lang";s:1:"1";s:4:"name";s:7:"charset";s:4:"span";s:9:",width180";}}i:4;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:20:"Header lines to skip";}s:1:"B";a:3:{s:4:"type";s:3:"int";s:4:"name";s:16:"num_header_lines";s:4:"size";s:1:"0";}}i:5;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:17:"Update categories";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:11:"update_cats";}}i:6;a:2:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:14:"Import data is";}s:1:"B";a:2:{s:4:"type";s:6:"select";s:4:"name";s:7:"convert";}}}s:4:"rows";i:6;s:4:"cols";i:2;}}','size' => '','style' => '.width180 select { width:150px;}','modified' => '1287425796',);
$templ_data[] = array('name' => 'importexport.wizard_basic_import_csv.conditions','template' => '','lang' => '','group' => '0','version' => '1.9.002','data' => 'a:1:{i:0;a:8:{s:4:"type";s:4:"vbox";s:4:"data";a:2:{i:0;a:0:{}i:1;a:4:{s:1:"A";a:2:{s:4:"type";s:6:"select";s:4:"name";s:14:"${row}[string]";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:2:{s:4:"type";s:6:"select";s:4:"name";s:12:"${row}[type]";}i:2;a:2:{s:4:"type";s:4:"text";s:4:"name";s:12:"${row}[op_2]";}}s:1:"C";a:2:{s:4:"type";s:6:"select";s:4:"name";s:12:"${row}[true]";}s:1:"D";a:2:{s:4:"type";s:6:"select";s:4:"name";s:13:"${row}[false]";}}}s:4:"rows";i:1;s:4:"cols";i:4;s:4:"size";s:1:"3";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:142:"How to merge with existing data? For each record, all conditions are evaluated from top to bottom, or stop. For blind insert, leave blank. ";}i:2;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:1:{s:2:"c1";s:2:"th";}i:1;a:6:{s:1:"A";a:2:{s:4:"type";s:5:"label";s:5:"label";s:5:"Field";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:5:"label";s:9:"Condition";}s:1:"C";a:5:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";s:4:"span";s:1:"2";i:1;a:4:{s:4:"type";s:5:"label";s:4:"span";s:1:"2";s:5:"label";s:4:"True";s:5:"align";s:6:"center";}i:2;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,2,0";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Action";}i:2;a:3:{s:4:"type";s:5:"label";s:5:"label";s:4:"Stop";s:5:"align";s:5:"right";}}}s:1:"D";a:1:{s:4:"type";s:5:"label";}s:1:"E";a:5:{s:4:"type";s:4:"vbox";s:4:"size";s:1:"2";s:4:"span";s:1:"2";i:1;a:4:{s:4:"type";s:5:"label";s:4:"span";s:1:"2";s:5:"label";s:5:"False";s:5:"align";s:6:"center";}i:2;a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,2,0";i:1;a:2:{s:4:"type";s:5:"label";s:5:"label";s:6:"Action";}i:2;a:3:{s:4:"type";s:5:"label";s:5:"label";s:4:"Stop";s:5:"align";s:5:"right";}}}s:1:"F";a:1:{s:4:"type";s:5:"label";}}i:2;a:6:{s:1:"A";a:4:{s:4:"type";s:6:"select";s:4:"name";s:14:"${row}[string]";s:4:"size";s:6:"Select";s:7:"no_lang";s:1:"1";}s:1:"B";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:3:{s:4:"type";s:6:"select";s:4:"name";s:12:"${row}[type]";s:7:"no_lang";s:1:"1";}i:2;a:3:{s:4:"type";s:4:"text";s:4:"name";s:12:"${row}[op_2]";s:7:"no_lang";s:1:"1";}}s:1:"C";a:4:{s:4:"type";s:6:"select";s:4:"name";s:20:"${row}[true][action]";s:4:"size";s:6:"Select";s:7:"no_lang";s:1:"1";}s:1:"D";a:3:{s:4:"type";s:8:"checkbox";s:5:"align";s:6:"center";s:4:"name";s:18:"${row}[true][stop]";}s:1:"E";a:4:{s:4:"type";s:6:"select";s:4:"name";s:21:"${row}[false][action]";s:4:"size";s:6:"Select";s:7:"no_lang";s:1:"1";}s:1:"F";a:4:{s:4:"type";s:8:"checkbox";s:5:"align";s:6:"center";s:4:"name";s:19:"${row}[false][stop]";s:4:"size";s:7:"1,false";}}}s:4:"rows";i:2;s:4:"cols";i:6;s:4:"name";s:10:"conditions";s:7:"options";a:0:{}}i:3;a:5:{s:4:"type";s:6:"button";s:4:"name";s:11:"button[add]";s:5:"label";s:3:"add";s:4:"help";s:27:"Add an additional condition";s:7:"onclick";s:37:"xajax_eT_wrapper(this); return false;";}}}','size' => '','style' => '','modified' => '1320350666',);

View File

@ -10,7 +10,7 @@
*/
$setup_info['importexport']['name'] = 'importexport';
$setup_info['importexport']['version'] = '1.9.003';
$setup_info['importexport']['version'] = '1.9.004';
$setup_info['importexport']['app_order'] = 2;
$setup_info['importexport']['enable'] = 2;
$setup_info['importexport']['tables'] = array('egw_importexport_definitions');
@ -57,3 +57,4 @@ $setup_info['importexport']['check_install'] = array(
),
);

View File

@ -25,7 +25,8 @@ $phpgw_baseline = array(
'plugin_options' => array('type' => 'longtext'),
'owner' => array('type' => 'int','precision' => '20'),
'description' => array('type' => 'varchar','precision' => '255'),
'modified' => array('type' => 'timestamp')
'modified' => array('type' => 'timestamp'),
'filter' => array('type' => 'longtext')
),
'pk' => array('definition_id'),
'fk' => array(),

View File

@ -100,3 +100,13 @@ function importexport_upgrade1_9_002()
return $GLOBALS['setup_info']['importexport']['currentver'] = '1.9.003';
}
function importexport_upgrade1_9_003()
{
$GLOBALS['egw_setup']->oProc->AddColumn('egw_importexport_definitions','filter',array(
'type' => 'longtext'
));
return $GLOBALS['setup_info']['importexport']['currentver'] = '1.9.004';
}

View File

@ -52,19 +52,44 @@
</grid>
</template>
<template id="importexport.export_dialog.selection_tab" template="" lang="" group="0" version="">
<grid height="200px">
<grid width="100%" height="200px">
<columns>
<column/>
<column width="150"/>
<column width="300" disabled="@no_filter"/>
</columns>
<rows>
<row class="th" height="20" disabled="@plugin_selectors_template">
<description/>
<description value="Definition filter"/>
</row>
<row valign="top" disabled="@plugin_selectors_template">
<html id="plugin_selectors_html" no_lang="1"/>
<box class="filters">
<filter id="filter"/>
</box>
</row>
<row>
<row class="th" height="20" disabled="!@plugin_selectors_template">
<description/>
<description value="Definition filter"/>
</row>
<row valign="top" disabled="!@plugin_selectors_template">
<template id="@plugin_selectors_template"/>
<box onclick="\$j('input[value=\'filter\']').not(':checked').attr('checked',true).parent().effect('highlight',{},2000);" class="filters">
<filter id="filter"/>
</box>
</row>
</rows>
</grid>
<styles>
select[multiple] {
width: 400px;
}
.filters {
max-height: 300px;
min-height: 150px;
overflow-y: auto;
}
</styles>
</template>
<template id="importexport.export_dialog.options_tab" template="" lang="" group="0" version="">
<grid height="200px">

View File

@ -0,0 +1,37 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<template id="importexport.wizard_basic_export_csv.choose_fields" template="" lang="" group="0" version="1.9.001">
<grid>
<columns>
<column/>
</columns>
<rows>
<row>
<description id="msg" span="all"/>
</row>
<row>
<grid overflow="auto" id="fields">
<columns>
<column/>
<column/>
</columns>
<rows>
<row class="th">
<description value="Field"/>
<hbox>
<description value="Export"/>
<buttononly statustext="Check all" label="Check all" id="check_all" needed="1" onclick="jQuery('input:checkbox').attr('checked', !jQuery('input:checkbox').attr('checked')); return false;" options="check"/>
</hbox>
</row>
<row>
<description id="${row}[name]" no_lang="1"/>
<checkbox id="export[${row}]" no_lang="1" options="{$row_cont[field]}"/>
</row>
</rows>
</grid>
</row>
</rows>
</grid>
</template>
</overlay>

View File

@ -0,0 +1,19 @@
<?xml version="1.0"?>
<!-- $Id$ -->
<overlay>
<template id="importexport.wizard_basic_export_csv.filter" template="" lang="" group="0" version="1.9.001">
<grid width="100%">
<columns>
<column/>
</columns>
<rows>
<row>
<filter id="set_filter" options="1"/>
</row>
</rows>
</grid>
<styles>select {
width: 200px;
}</styles>
</template>
</overlay>