From 16347125b10bdb92f0ae5e172769b64921b293a0 Mon Sep 17 00:00:00 2001 From: sparkyx Date: Sun, 11 Aug 2024 10:37:43 +0200 Subject: [PATCH] widget : Creation of widget for the DASHBOARD Contains widget Agenda, Todo List, Report ,... --- html/ajax_misc.php | 10 + html/css/style-classic7.css | 130 ++++++- html/js/noalyss_script.js | 271 +++++++++++++- html/js/todo_list.js | 8 +- include/ajax/ajax_preference.php | 19 - include/class/acc_ledger.class.php | 7 +- include/class/noalyss_user.class.php | 31 -- include/constant.php | 3 +- include/dashboard.inc.php | 17 +- include/template/calendar.php | 7 +- include/template/dashboard.php | 212 ++--------- .../status_operation_event-main_display.php | 2 +- include/widget/agenda/agenda.php | 55 +++ include/widget/ajax.php | 140 ++++++++ include/widget/bookmark/bookmark.php | 72 ++++ include/widget/bookmark/install.php | 33 ++ include/widget/coming_event/coming_event.php | 44 +++ include/widget/event/event-display.php | 54 +++ include/widget/event/event.php | 71 ++++ include/widget/event/install.php | 33 ++ include/widget/invoice/install.php | 33 ++ include/widget/invoice/invoice-display.php | 64 ++++ include/widget/invoice/invoice.php | 82 +++++ .../widget/last_event/last_event-display.php | 46 +++ include/widget/last_event/last_event.php | 51 +++ .../last_operation/last_operation-display.php | 54 +++ .../widget/last_operation/last_operation.php | 49 +++ include/widget/mini_report/mini_report.php | 120 +++++++ .../todo_list/todo_list-display_new_note.php | 45 +++ include/widget/todo_list/todo_list.php | 77 ++++ include/widget/widget-development.md | 108 ++++++ include/widget/widget.php | 335 ++++++++++++++++++ sql/upgrade.sql | 59 +++ 33 files changed, 2067 insertions(+), 275 deletions(-) create mode 100644 include/widget/agenda/agenda.php create mode 100644 include/widget/ajax.php create mode 100644 include/widget/bookmark/bookmark.php create mode 100644 include/widget/bookmark/install.php create mode 100644 include/widget/coming_event/coming_event.php create mode 100644 include/widget/event/event-display.php create mode 100644 include/widget/event/event.php create mode 100644 include/widget/event/install.php create mode 100644 include/widget/invoice/install.php create mode 100644 include/widget/invoice/invoice-display.php create mode 100644 include/widget/invoice/invoice.php create mode 100644 include/widget/last_event/last_event-display.php create mode 100644 include/widget/last_event/last_event.php create mode 100644 include/widget/last_operation/last_operation-display.php create mode 100644 include/widget/last_operation/last_operation.php create mode 100644 include/widget/mini_report/mini_report.php create mode 100644 include/widget/todo_list/todo_list-display_new_note.php create mode 100644 include/widget/todo_list/todo_list.php create mode 100644 include/widget/widget-development.md create mode 100644 include/widget/widget.php diff --git a/html/ajax_misc.php b/html/ajax_misc.php index bb676e1e3..7f4a49dc3 100644 --- a/html/ajax_misc.php +++ b/html/ajax_misc.php @@ -143,6 +143,16 @@ if ( LOGINPUT) fwrite($file_loginput,"include '".basename(__FILE__)."';\n"); fclose($file_loginput); } + +/** + * for widget we call immediately a file outside the ajax folder + */ +if ($op == 'widget') { + session_write_close(); + require_once NOALYSS_INCLUDE.'/widget/ajax.php'; + return; +} + $path = array( // search accounting , detail ... "account"=>"ajax_poste", diff --git a/html/css/style-classic7.css b/html/css/style-classic7.css index 186268a2b..940c1606c 100644 --- a/html/css/style-classic7.css +++ b/html/css/style-classic7.css @@ -405,9 +405,7 @@ tr.odd > td,tr.even > td { tr.highlight { font-weight: bold; } -div.even,tr.even { - /*! background-color: #F7F8FC; */ -} + td.odd{ background-color:#DDE6FF; } @@ -813,7 +811,7 @@ div.content div.pc_calendar tr{ } @media only screen and (min-width: 640px) { div.pc_calendar tr{ - height:110px; + height:10%; } } @media only screen and (max-width: 640px) { @@ -1449,6 +1447,12 @@ h2.title { font-family: OpenSansRegular; margin-bottom: 1px; } + + .box h2.title { + font-size: 1rem; + font-variant-caps: normal; + } + h3.title { color: #0000FF; margin-left: 30px; @@ -1802,9 +1806,6 @@ div.box { font-size:0.90rem; border-radius:5px; width:97%; - margin:1% 1.5% 1% 1.5%; - margin-right:2px - } /* SM */ @media (min-width: 576px) { @@ -1819,16 +1820,17 @@ div.box { @media (min-width: 992px) { div.box { width: 46%; - margin: 1.5%; + height:40%; } } /* XL */ @media (min-width: 1200px) { div.box { - width: 32.8%; - margin: 0.2%; + width: 35rem; + max-height: 30%; + height: 45vh; } } @@ -1836,14 +1838,18 @@ div.box { div.box table{ border-spacing:0px; font-size: 96%; + width: 80%; } -div.box tr.odd { - background-color: lightblue; - +div.odd, div.box tr.odd { + background-color: #dce7f5; + border: 1px solid whitesmoke; + padding:2px; + } -div.box tr.even { +div.even ,div.box tr.even { background-color: white; - + border: 1px solid whitesmoke; + padding:2px; } #jrn_name_div h2{ font-size:38.4px; @@ -3462,4 +3468,98 @@ li.li-active { .hoverclass-drag { background-color: white; + } + + + /********************************************************************************************************************** + * User's widget list + * + *********************************************************************************************************************/ + #widget_box_id { + #widget_box_id { + width: 100%; + margin-left: 0px; + margin-right: 0px; + } + } + + #contain_widget li { + padding : 0.75rem; + margin:2px; + border:navy solid 1px; + } + + #widget_add li { + padding : 0.75rem; + margin:2px; + border:navy solid 1px; + } + + + @media (min-width: 576px) { + + + } + /* MeDium */ + @media (min-width: 768px) { + #widget_box_id { + width: 100%; + margin-left: 0px; + margin-right: 0px; + } + } + + /* LarGe */ + @media (min-width: 992px) { + #widget_box_id { + width: 70%; + margin-left: 15%; + + } + } + /* eXtraLarge */ + @media (min-width: 1200px) { + + } +span.widget-name { + font-size:105%; + font-family: bold; + font-stretch: extra-expanded; + margin-right: 2rem; + margin-top: -5px; + width: 5rem; + display: inline-block; + +} + + #dashboard_div_id { + margin-top:2vh; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: center; + row-gap: 20px; + column-gap: 20px; + } + + /* + * WIDGET + */ + #widget_box_select_id { + max-width: 70rem; + } + #widget_box_id { + max-width: 70rem; + + } + .widget_param { + font-size: 105%; + font-weight: bold; + font-style: inherit; + border-width: 1px; + display: inline-block; + border-color: navy; + padding: 5px; + border-style: groove; + margin: 2px; } \ No newline at end of file diff --git a/html/js/noalyss_script.js b/html/js/noalyss_script.js index e21663ea0..2b2ec4dcb 100644 --- a/html/js/noalyss_script.js +++ b/html/js/noalyss_script.js @@ -2886,11 +2886,11 @@ function calendar_zoom(obj) { obj.outdiv = 'calendar_zoom_div'; } if ($(obj.outdiv) == undefined) { - var str_style = 'top:10%;margin-left:2%;'; + var str_style = 'top:10%;min-height:60rem'; // var str_style = fixed_position(0, 120); add_div({ id: obj.outdiv, - style: 'margin-left:3%;width:94%;' + str_style, + style: 'width:94%;' + str_style, cssclass: "inner_box", drag: 0 }); @@ -4323,3 +4323,270 @@ function activate_plugin(elt) alert_box(e.message); } } +/**********************************************************************************************************************/ +/** + * @class Widget + */ +/**********************************************************************************************************************/ + +Widget = function(dossier_id) { + this.dossier_id=dossier_id; +} +/** + * Display the widget in the elt box + * @param box DOMID of the target + * @param dossier_id + * @param user_widget_id + * @param widget_code + */ +Widget.prototype.display = function (box,user_widget_id,widget_code) { + try { + + var queryString = { + gDossier: this.dossier_id, + 'op': 'widget', + 'user_widget_id': user_widget_id, + 'widget_code': widget_code, + 'action': 'widget.display' + } + var action = new Ajax.Request( + "ajax_misc.php", + { + method: 'GET', + parameters: queryString, + onFailure: ajax_misc_failure, + onSuccess: function (req) { + if (req.responseText == 'NOCONX') { + reconnect(); + return; + } + $(box).replace(req.responseText); + + } + } + ); + } catch (e) { + alert_box(e.message); + } + +} + +/** + * Manage the widget + * @param dossier_id + * @returns {boolean} + */ +Widget.prototype.manage = function () { + try { + var box = 'widget_box_id'; + var queryString = { + gDossier: this.dossier_id, + 'op': 'widget', + 'action': 'widget.manage' + } + var action = new Ajax.Request( + "ajax_misc.php", + { + method: 'GET', + parameters: queryString, + onFailure: ajax_misc_failure, + onSuccess: function (req) { + if (req.responseText == 'NOCONX') { + reconnect(); + return; + } + var style = 'position:absolute;'; + var y = calcy(200); + style = style + ' ;top : ' + y + 'px'; + + add_div({id: box, cssclass: 'inner_box', html: loading(), style: style}) + + $(box).update(req.responseText); + + } + } + ); + } catch (e) { + alert_box(e.message); + console.error("widget_manage" + e.message); + } + return false; +} +/** + * create a list of sortable elements + */ +Widget.prototype.create_sortable=function() { + + Sortable.create('contain_widget',{tag:'li',onUpdate:function(){ $('order_widget_hidden').value=Sortable.serialize('contain_widget')}}) + $('order_widget_hidden').value=Sortable.serialize('contain_widget'); +} +/** + * Save the order of widget + **/ +Widget.prototype.save = function () { + try + { + var here = this; + var dgbox="widget_box_id"; + waiting_box(); + + // For form , most of the parameters are in the FORM + // method is then POST + //var queryString=$(p_form_id).serialize(true); + + var queryString = { + op : 'widget', + action : 'widget.save', + gDossier: this.dossier_id, + param : Sortable.serialize('contain_widget') + }; + var action = new Ajax.Request( + "ajax_misc.php" , + { + method:'GET', + parameters:queryString, + onFailure:ajax_misc_failure, + onSuccess:function(req){ + remove_waiting_box(); + if (req.responseText == 'NOCONX') { + reconnect(); + return; + } + removeDiv(dgbox) + here.refresh(); + + } + } + ); + }catch( e) + { + alert_box(e.message); + } +} +/** + * refresh the DASHBOARD (dashboard_div_id) + */ +Widget.prototype.refresh = function () { + try { + var dgbox='dashboard_div_id' + var queryString = { + op : 'widget', + action : 'widget.refresh', + gDossier: this.dossier_id + }; + var action = new Ajax.Request( + "ajax_misc.php" , + { + method:'GET', + parameters:queryString, + onFailure:ajax_misc_failure, + onSuccess:function(req){ + if (req.responseText == 'NOCONX') { + reconnect(); + return; + } + + $(dgbox).replace(req.responseText); + + } + } + ); + }catch( e) { + console.error("widget.refresh "+e.message) + } +} +/** + * delete a widget : remove from the list + * @param user_widget_id {integer} + */ +Widget.prototype.delete=function (user_widget_id) { + $('elt_'+user_widget_id).remove() + $('order_widget_hidden').value=Sortable.serialize('contain_widget'); +} +/** + * display list widget we can add + */ +Widget.prototype.input = function () { + try { + var box="widget_box_select_id"; + + var queryString = { + op: 'widget', + action: 'widget.input', + gDossier: this.dossier_id + }; + var action = new Ajax.Request( + "ajax_misc.php", + { + method: 'GET', + parameters: queryString, + onFailure: ajax_misc_failure, + onSuccess: function (req) { + remove_waiting_box(); + if (req.responseText == 'NOCONX') { + reconnect(); + return; + } + var style = 'position:absolute;'; + var y = calcy(200); + style = style + ' ;top : ' + y + 'px'; + + add_div({id: box, cssclass: 'inner_box', html: loading(), style: style}) + + $(box).update(req.responseText); + + + } + } + ); + } catch (e) { + alert_box(e.message); + } +} +/** + * add a widget for the user , refresh the dashboard afterward + * @param widget_code {string} + */ +Widget.prototype.add=function (widget_code) { + try + { + here=this; + var param = {}; + if ($(widget_code+"_param")) { + console.debug(`found a FORM`) + param=$(widget_code+"_param").serialize() + } + query = { + op : 'widget', + action : 'widget.insert', + gDossier: this.dossier_id, + param : param, + widget_code:widget_code + } + var action = new Ajax.Request( + "ajax_misc.php" , + { + method:'GET', + parameters:query, + onFailure:ajax_misc_failure, + onSuccess:function(req){ + if (req.responseText == 'NOCONX') { + reconnect(); + return; + } + var new_element=new Element("li"); + $('contain_widget').appendChild(new_element); + new_element.replace(req.responseText) + removeDiv('widget_box_select_id') + here.create_sortable() + here.refresh() + + } + } + ); + }catch( e) + { + alert_box(e.message); + } + +} \ No newline at end of file diff --git a/html/js/todo_list.js b/html/js/todo_list.js index c22eb30ea..426da8736 100644 --- a/html/js/todo_list.js +++ b/html/js/todo_list.js @@ -185,11 +185,11 @@ function zoom_todo () waiting_box(); if ( ! todo_maximize) { - var clonetodo=$('todo_listg_div').clone(); + var clonetodo=$('todo_list').clone(); clonetodo.setAttribute('id','clone_todo_list') clonetodo.setStyle({'z-index':1,'position':'absolute','width':'95%','height':'95%','top':'2%','right':'2%','left':'2%'}) - clonetodo.innerHTML=$('todo_listg_div').innerHTML; - $('todo_listg_div').innerHTML=""; + clonetodo.innerHTML=$('todo_list').innerHTML; + $('todo_list').innerHTML=""; clonetodo.addClassName('inner_box'); clonetodo.removeClassName('box'); document.body.appendChild(clonetodo); @@ -197,7 +197,7 @@ function zoom_todo () } else { todo_maximize=false; - $('todo_listg_div').innerHTML=$('clone_todo_list').innerHTML; + $('todo_list').innerHTML=$('clone_todo_list').innerHTML; $('clone_todo_list').remove(); } diff --git a/include/ajax/ajax_preference.php b/include/ajax/ajax_preference.php index f66c6cb99..719bf21f4 100644 --- a/include/ajax/ajax_preference.php +++ b/include/ajax/ajax_preference.php @@ -257,23 +257,6 @@ if ( $action == 'display_form' ) '; - echo '' . _('Options pour la page d\'accueil') . ''; - echo _('Mini-Rapport : '); - $rapport = new Acc_Report($cn); - $aRapport = $rapport->make_array(); - $aRapport[] = array("value" => 0, "label" => _('Aucun mini rapport')); - $wRapport = new ISelect(); - $wRapport->name = "minirap"; - $wRapport->selected = $g_user->get_mini_report(); - $wRapport->value = $aRapport; - echo $wRapport->input(); - echo '' . _('Le mini rapport est un rapport qui s\'affiche sur votre page d\'accueil') . ''; - echo ''; - } echo '
'; echo '' . _('Langue') . ''; @@ -351,10 +334,8 @@ if ($action == 'save') } if ( $inside_dossier) { - $minirap=$http->post("minirap","number","0"); $period=$http->post("period","number"); $g_user->set_periode($period); - $g_user->set_mini_report($minirap); } $g_user->save_global_preference('THEME', $style_user); $g_user->save_global_preference('LANG', $lang); diff --git a/include/class/acc_ledger.class.php b/include/class/acc_ledger.class.php index 2f08d0063..488c81182 100644 --- a/include/class/acc_ledger.class.php +++ b/include/class/acc_ledger.class.php @@ -3158,9 +3158,11 @@ class Acc_Ledger extends jrn_def_sql default: throw new Exception('Ledger_type invalid : '.$p_ledger_type); } + if ( ! in_array($sql_op ,array('>','<','=','>=','<='))) { + throw new \Exception ("AC3162 : invalid \$sql_op = [$sql_op]"); + } - - $sql="select jr_id, jr_internal, jr_date, jr_comment,jr_pj_number,jr_montant + $sql="select jr_id, jr_internal, jr_date, jr_comment,jr_pj_number,jr_montant,jr_ech from jrn join jrn_def on (jrn_def_id=jr_def_id) where @@ -3168,6 +3170,7 @@ class Acc_Ledger extends jrn_def_sql and jr_ech $sql_op to_date($1,'DD.MM.YYYY') and coalesce (jr_rapt,'xx') <> 'paid' and $filter + order by jr_date "; $array=$this->db->get_array($sql, array($p_date)); return $array; diff --git a/include/class/noalyss_user.class.php b/include/class/noalyss_user.class.php index 1d45d33a6..250ec4733 100644 --- a/include/class/noalyss_user.class.php +++ b/include/class/noalyss_user.class.php @@ -752,37 +752,6 @@ class Noalyss_User return $array['PERIODE']; } - /** - * - * \brief return the mini rapport to display on the welcome page - * \return 0 if nothing if found or the report to display (form_definition.fr_id) - */ - function get_mini_report() - { - $array=$this->get_preference(); - $fr_id=(isset($array['MINIREPORT']))?$array['MINIREPORT']:0; - return $fr_id; - } - - /** - * \brief set the mini rapport to display on the welcome page - */ - function set_mini_report($p_id) - { - $count=$this->db->get_value("select count(*) from user_local_pref where user_id=$1 and parameter_type=$2", - array($this->id, 'MINIREPORT')); - if ($count==1) - { - $sql="update user_local_pref set parameter_value=$1 where user_id=$2 and parameter_type='MINIREPORT'"; - $Res=$this->db->exec_sql($sql, array($p_id, $this->id)); - } - else - { - $sql="insert into user_local_pref (user_id,parameter_type,parameter_value)". - "values($1,'MINIREPORT',$2)"; - $Res=$this->db->exec_sql($sql, array($this->id, $p_id)); - } - } /** * @brief Save the preference , the scope is global, the settings are saved diff --git a/include/constant.php b/include/constant.php index 3c08813d5..6ceb328f1 100644 --- a/include/constant.php +++ b/include/constant.php @@ -406,7 +406,8 @@ function noalyss_class_autoloader($class) "htmlinput" => "lib/html_input.class.php", 'noalyss\dbg'=>"lib/dbg.php", 'noalyss\file_cache'=>"lib/file_cache.class.php", - "pdfland"=>"class/pdf_land.class.php" + "pdfland"=>"class/pdf_land.class.php", + "noalyss\widget\widget"=>"widget/widget.php" ); if (isset ($aClass[$class])) { require_once NOALYSS_INCLUDE . "/" . $aClass[$class]; diff --git a/include/dashboard.inc.php b/include/dashboard.inc.php index b0f0e1e43..2a00531bc 100644 --- a/include/dashboard.inc.php +++ b/include/dashboard.inc.php @@ -4,21 +4,10 @@ if ( ! defined ('ALLOWED') ) die('Appel direct ne sont pas permis'); *@file *@brief Dashboard */ -require_once NOALYSS_INCLUDE.'/constant.php'; -require_once NOALYSS_INCLUDE.'/lib/ac_common.php'; -require_once NOALYSS_INCLUDE.'/lib/user_menu.php'; - -echo '
'; -global $g_user; -/* others report */ -$cal=new Calendar(); -$cal->get_preference(); - -$obj=sprintf("{gDossier:%d,invalue:'%s',outdiv:'%s','distype':'%s'}", - dossier::id(),'per','calendar_zoom_div','cal'); - - require_once NOALYSS_TEMPLATE.'/dashboard.php'; +echo \HtmlInput::button_action(_('Elements du tableau de bord'), "widget.manage()"); + + ?> diff --git a/include/template/calendar.php b/include/template/calendar.php index fe2fa9bb2..76ca5ad9a 100644 --- a/include/template/calendar.php +++ b/include/template/calendar.php @@ -12,9 +12,9 @@ ?> - +
-
+
day) { if ($nCol==0) { - echo ""; + echo ""; } $class="workday"; if ($week==0||$week==6) diff --git a/include/template/dashboard.php b/include/template/dashboard.php index 558ccc9b3..9330d0645 100644 --- a/include/template/dashboard.php +++ b/include/template/dashboard.php @@ -1,197 +1,43 @@ - -
-
- -display('short',0); ?> -
- -
load_all(); -$a_todo=Todo_List::to_object($cn,$array); - -echo HtmlInput::button('add',_('Ajout'),'onClick="add_todo()"','smallbutton'); - echo '
'; - echo ''; -if ( ! empty ($array) ) { - $nb=0; - $today=date('d.m.Y'); - - foreach ($a_todo as $row) { - if ( $nb % 2 == 0 ) $odd='odd '; else $odd='even '; - $nb++; - echo $row->display_row($odd); - } -} - echo '
DateTitre
'; -?> -
- -
- -
- - - +/** + * @file + * @brief : display all available widgets for the connected user */ -$report=$g_user->get_mini_report(); +global $g_user,$cn; +use \Noalyss\Widget\Widget; -$rapport=new Acc_Report($cn,$report); +$aWidget=\Noalyss\Widget\Widget::get_enabled_widget(); -if ( $rapport->exist() == false ) { - $g_user->set_mini_report(0); - $report=0; -} -if ( $report != 0 ) : ?> -
get_name(),'report_div','none','','n');?> -get_exercice(); - if ( $exercice == 0 ) { - alert(_('Aucune periode par defaut')); - } else { - $periode=new Periode($cn); - $limit=$periode->limit_year($exercice); - - $result=$rapport->get_row($limit['start'],$limit['end'],'periode'); - $ix=0; - if ( !empty ($result ) && count ($result) > 0) - { - echo ''; - foreach ($result as $row) { - $ix++; - $class=($ix%2==0)?' class="even" ':' class="odd" '; - echo ''; - - echo ''; - $style='style="text-align:right;"'; - if ($row['montant']<0) { $style='style="color:red;text-align:right;"';} - echo ""; - echo ''; - } - echo '
'.$row['desc'].'".nbm($row['montant'])."
'; - } else { - echo _('Aucun résultat'); - } - } - ?> -
- -
-

- -

-

+
+ +for ($i=0;$i < $nb ;$i++): + $widget=Widget::build_user_widget($aWidget[$i]['uw_id'],$aWidget[$i]['wd_code']); + Widget::ajax_display($widget); - - - - -
- - - -get_last(20); - -for($i=0;$i -> - - - - - - - - -
- - - - - - - - - - -
- -
-
- - get_last(MAX_ACTION_SHOW); - $len_array=count($array); - ?> - - - - - - - - - -
- - - - - - - -
-
-
- - diff --git a/include/template/status_operation_event-main_display.php b/include/template/status_operation_event-main_display.php index f2e504383..c1018eb82 100644 --- a/include/template/status_operation_event-main_display.php +++ b/include/template/status_operation_event-main_display.php @@ -38,7 +38,7 @@ $customer_late=$Ledger->get_customer_late(); $gDossier_id=Dossier::id(); ?> - +
diff --git a/include/widget/agenda/agenda.php b/include/widget/agenda/agenda.php new file mode 100644 index 000000000..530811993 --- /dev/null +++ b/include/widget/agenda/agenda.php @@ -0,0 +1,55 @@ + +/** + * @file + * @brief : widget agenda, + * @note this widget is included in Noalyss Core and a part of the code (javascript + css + ajax) + * are still included in NOALYSS Code + */ +namespace Noalyss\Widget; + +/*! + * \class Agenda + * \brief : widget agenda, + * \note this widget is included in Noalyss Core and a part of the code (javascript + css + ajax) + * are still included in NOALYSS Code, this code should move here and will be part of a "cleansing code" process +*/ +class Agenda extends Widget +{ + + function display() + { + global $g_user; + /* others report */ + $cal=new \Calendar(); + $cal->get_preference(); + + $obj=sprintf("{gDossier:%d,invalue:'%s',outdiv:'%s','distype':'%s'}", + \Dossier::id(),'per','calendar_zoom_div','cal'); + + $this->open_div(); + echo \HtmlInput::title_box(_('Calendrier'),'cal_div','zoom',"calendar_zoom($obj)",'n'); + echo $cal->display('short',0); + $this->close_div(); + } + + + +} \ No newline at end of file diff --git a/include/widget/ajax.php b/include/widget/ajax.php new file mode 100644 index 000000000..b3dd83897 --- /dev/null +++ b/include/widget/ajax.php @@ -0,0 +1,140 @@ +request("action"); + $w=$http->request("w","string","widget"); +} catch (\Exception $e) { + echo $e->getMessage(); +} + +// action = display, +if ($action == 'widget.display') { + try { + $widget=\Noalyss\Widget\Widget::build_user_widget($http->request('user_widget_id'),$http->request("widget_code")); + $widget?->display(); + + } catch (\Exception $e) { + echo $e->getMessage(); + } + + return; +} +// call from a widget +if ( $w != "widget") { + // security + // widget exists ? Protect against attack when w is a relative path to something else + $count=$cn->get_value("select count(*) from widget_dashboard where wd_code=$1",[$w]); + if ($count == 1 && file_exists(NOALYSS_INCLUDE."/widget/$w/ajax.php")) { + require NOALYSS_INCLUDE."/widget/$w/ajax.php"; + return; + } +} +// action == manage , display a dialog box to add , remove or change parameter of widget +// if must possible to add several time the same widget , example mini-report +if ( $action == 'widget.manage') { + echo \HtmlInput::title_box(_("Elements"), 'widget_box_id'); + echo '
'; + echo span(_('Organiser les éléments en utilisant la souris (Drag & Drop) puis sauver'),'class="text-muted text-center"'); + \Noalyss\Widget\Widget::display_available(); + + + echo '
    '; + echo '
  • '.\HtmlInput::button_close('widget_box_id','button').'
  • '; + echo '
  • '.\HtmlInput::button_action(_('Sauver'),'widget.save()').'
  • '; + echo '
  • '.\HtmlInput::button_action(_('Ajouter'),'widget.input()').'
  • '; + + echo '
      '; + + echo create_script("widget.create_sortable()"); + echo '
'; + return; +} +/************************************************************************** + * +// save the order of the widget + *************************************************************************/ +if ( $action == 'widget.save') { + $query=$http->request("param","string",""); + try { + parse_str($query, $aWigdet); + \Noalyss\Widget\Widget::save($aWigdet['contain_widget']); + + } catch (\Exception $e) { + echo "NOK"; + echo $e->getMessage(); + } + return; +} +/************************************************************************** + * refresh dashboard + * + *************************************************************************/ +if ($action == 'widget.refresh') { + require NOALYSS_TEMPLATE."/dashboard.php"; + return; +} +if ($action == "widget.input") { + echo \HtmlInput::title_box(_("Elements à ajouter"), 'widget_box_select_id'); + echo '
'; + \Noalyss\Widget\Widget::select_available(); + echo '
'; + echo '
    '; + echo '
  • '.\HtmlInput::button_close('widget_box_select_id','button').'
  • '; + echo '
      '; + echo ''; + return; +} +/************************************************************************* + * insert a new widget with param if any + ************************************************************************/ +if ($action == 'widget.insert') { + // insert new widget in user_widget + list "contain_widget" + $param = $http->request("param","string",null); + $widget_code = $http->request("widget_code"); + $widget_id=$cn->get_value("select wd_id from widget_dashboard where wd_code=$1 ",[$widget_code]); + if (empty($widget_id)) return; + + $user_widget_id = $cn->get_value("insert into user_widget(use_login,dashboard_widget_id,uw_parameter,uw_order) +values ($1,$2,$3,1000) returning uw_id",[$g_user->getLogin(),$widget_id,$param]); + $widget=\Noalyss\Widget\Widget::build_user_widget($user_widget_id, $widget_code); + $widget->input(); + return; +} \ No newline at end of file diff --git a/include/widget/bookmark/bookmark.php b/include/widget/bookmark/bookmark.php new file mode 100644 index 000000000..da9175f47 --- /dev/null +++ b/include/widget/bookmark/bookmark.php @@ -0,0 +1,72 @@ +open_div(); + echo '

      ',_("Favoris"),'✨','

      '; + $bookmark_sql="select distinct b_id,b_action,b_order,me_code,me_description, javascript" + . " from bookmark " + . "join v_menu_description_favori on (code=b_action or b_action=me_code)" + . "where " + . "login=$1 order by me_code"; + $a_bookmark=$this->db->get_array($bookmark_sql,array($g_user->login)); + + $dossier_id=\Dossier::id(); + if (count($a_bookmark) >0 ) { + $p=0; + foreach ($a_bookmark as $item) { + $a_code= explode('/',$item['b_action']); + $idx=count($a_code); + $code=$a_code[$idx-1]; + $url=http_build_query(array("ac"=>$item['b_action'],"gDossier"=>$dossier_id)); + $p++; + $class=($p&1)?' odd ':'even'; + $description=h($item['me_description']); + echo << +
      + + + {$code} +
      +
      + + + {$description} +
      + +EOF; + + } + } + $this->close_div(); + + } + +} \ No newline at end of file diff --git a/include/widget/bookmark/install.php b/include/widget/bookmark/install.php new file mode 100644 index 000000000..463eb4cc5 --- /dev/null +++ b/include/widget/bookmark/install.php @@ -0,0 +1,33 @@ +exec_sql("insert into widget_dashboard (wd_code,wd_description,wd_parameter,wd_name) values ($1,$2,$3,$4)", + array ( + 'bookmark' + ,'Raccourcis vers vos menus préférés' + ,0 + ,'Raccourcis' + ) +); diff --git a/include/widget/coming_event/coming_event.php b/include/widget/coming_event/coming_event.php new file mode 100644 index 000000000..312f4937d --- /dev/null +++ b/include/widget/coming_event/coming_event.php @@ -0,0 +1,44 @@ +open_div(); + \Status_Operation_Event::main_display($cn); + $this->close_div(); + } + +} diff --git a/include/widget/event/event-display.php b/include/widget/event/event-display.php new file mode 100644 index 000000000..27c7130da --- /dev/null +++ b/include/widget/event/event-display.php @@ -0,0 +1,54 @@ + +
      +
      + +
      +
      + +
      +
      + + + diff --git a/include/widget/event/event.php b/include/widget/event/event.php new file mode 100644 index 000000000..63c43d410 --- /dev/null +++ b/include/widget/event/event.php @@ -0,0 +1,71 @@ +db,'R') + ." order by ag_remind_date asc"; + $array=$this->db->get_array($sql); + return $array; + } + + function display() + { + + $this->open_div(); + $array=$this->get_next10(); + require "event-display.php"; + + $this->close_div(); + } +} \ No newline at end of file diff --git a/include/widget/event/install.php b/include/widget/event/install.php new file mode 100644 index 000000000..9120cf054 --- /dev/null +++ b/include/widget/event/install.php @@ -0,0 +1,33 @@ +exec_sql("insert into widget_dashboard (wd_code,wd_description,wd_parameter,wd_name) values ($1,$2,$3,$4)", + array ( + 'event' + ,'Affiche les actions à venir et celles en retards' + ,0 + ,'A faire' + ) +); diff --git a/include/widget/invoice/install.php b/include/widget/invoice/install.php new file mode 100644 index 000000000..308e0a3b6 --- /dev/null +++ b/include/widget/invoice/install.php @@ -0,0 +1,33 @@ +exec_sql("insert into widget_dashboard (wd_code,wd_description,wd_parameter,wd_name) values ($1,$2,$3,$4)", + array ( + 'invoice' + ,'Affiche les prochaines factures fournisseurs ou clients ou en retard' + ,1 + ,'Factures' + ) +); diff --git a/include/widget/invoice/invoice-display.php b/include/widget/invoice/invoice-display.php new file mode 100644 index 000000000..6870ef6a2 --- /dev/null +++ b/include/widget/invoice/invoice-display.php @@ -0,0 +1,64 @@ +format('ymd')>$ech->format('ymd') ) + continue; + $p++; + $class=($p&1)?' odd ':'even'; +?> +
      +
      + format('d.m.y')?> +
      +
      + +
      +
      + + +
      +
      + +
      +
      + + + diff --git a/include/widget/invoice/invoice.php b/include/widget/invoice/invoice.php new file mode 100644 index 000000000..0289821f3 --- /dev/null +++ b/include/widget/invoice/invoice.php @@ -0,0 +1,82 @@ +value[] = array('value' => 'S', 'label' => _("Fournisseurs")); + $tiers->value[] = array('value' => 'C', 'label' => _("Clients")); + $time_limit = new \ISelect('time_limit'); + $time_limit->value[] = array('value' => 'P', 'label' => _("Prochaines factures")); + $time_limit->value[] = array('value' => 'R', 'label' => _("Factures en retard")); + $time_limit->value[] = array('value' => 'T', 'label' => _("Factures pour aujourd'hui")); + + $input = _("Factures ") . $tiers->input() . " " . _("échéance") . " " . $time_limit->input(); + $this->make_form($input); + + } + + function display_parameter() + { + $aParam = $this->get_parameter(); + $aTiers = ['S' => _("Fournisseurs"), "C" => _("Clients")]; + $aLimit = ['P' => _("Prochaines"), "R" => "Retard",'T'=>_("Aujourd'hui")]; + echo ''.$aTiers[$aParam['tiers']] . " " . $aLimit[$aParam["time_limit"]].''; + } + + function display() + { + $this->open_div(); + $aParam = $this->get_parameter(); + $aTiers = ['S' => _("Fournisseurs"), "C" => _("Clients")]; + $aLimit = ['P' => _("Prochaines factures"), "R" => "facture en retard",'T'=>_("Aujourd'hui")]; + $title = $aTiers[$aParam['tiers']] . " " . $aLimit[$aParam["time_limit"]]; + echo h2($title, 'class="title"'); + $acc_ledger = new \Acc_Ledger($this->db, 0); + + $ledger_type = 'ACH'; + if ($aParam['tiers'] == 'C') { + $ledger_type = 'VEN'; + } + + switch ($aParam['time_limit']) { + case 'P': + $array = $acc_ledger->get_operation_date(date('d.m.Y'), $ledger_type, '>'); + break; + case 'R': + $array = $acc_ledger->get_operation_date(date('d.m.Y'), $ledger_type, '<'); + break; + case 'T': + $array = $acc_ledger->get_operation_date(date('d.m.Y'), $ledger_type, '='); + break; + } + include "invoice-display.php"; + $this->close_div(); + + + } +} \ No newline at end of file diff --git a/include/widget/last_event/last_event-display.php b/include/widget/last_event/last_event-display.php new file mode 100644 index 000000000..f2b3279db --- /dev/null +++ b/include/widget/last_event/last_event-display.php @@ -0,0 +1,46 @@ + + + + + + + + + + +
      + + + + + + + +
      \ No newline at end of file diff --git a/include/widget/last_event/last_event.php b/include/widget/last_event/last_event.php new file mode 100644 index 000000000..02af98855 --- /dev/null +++ b/include/widget/last_event/last_event.php @@ -0,0 +1,51 @@ +open_div(); + echo HtmlInput::title_box(_('Suivi'),"last_operation_management_div",'zoom','action_show('.dossier::id().')','n'); + $gestion=new \Follow_Up($cn); + $array=$gestion->get_last(MAX_ACTION_SHOW); + $len_array=count($array); + include "last_event-display.php"; + $this->close_div(); + } + +} \ No newline at end of file diff --git a/include/widget/last_operation/last_operation-display.php b/include/widget/last_operation/last_operation-display.php new file mode 100644 index 000000000..e0805929f --- /dev/null +++ b/include/widget/last_operation/last_operation-display.php @@ -0,0 +1,54 @@ + + + get_last(20); + + for ($i = 0; $i < count($last_ledger); $i++): + $class = ($i % 2 == 0) ? ' class="even" ' : ' class="odd" '; + ?> + > + + + + + + + + +
      + + + + + + + + + + +
      \ No newline at end of file diff --git a/include/widget/last_operation/last_operation.php b/include/widget/last_operation/last_operation.php new file mode 100644 index 000000000..7fdb4f994 --- /dev/null +++ b/include/widget/last_operation/last_operation.php @@ -0,0 +1,49 @@ +open_div(); + + echo \HtmlInput::title_box(_('Dernières opérations'),"last_operation_box_div",'zoom','popup_recherche('.\Dossier::id().')','n'); + require_once "last_operation-display.php"; + $this->close_div(); + } + +} \ No newline at end of file diff --git a/include/widget/mini_report/mini_report.php b/include/widget/mini_report/mini_report.php new file mode 100644 index 000000000..d703ccfe9 --- /dev/null +++ b/include/widget/mini_report/mini_report.php @@ -0,0 +1,120 @@ +db->get_value("select uw_parameter from user_widget where uw_id=$1",[$this->user_widget_id]); + parse_str($param, $aReport); + $report=$aReport['simple_report']; + $rapport = new \Acc_Report($cn, $report); + + if ($rapport->exist() == false) { + $report = 0; + } + $this->open_div(); + if ($report != 0) { + ?> + get_name(), 'report_div', 'none', '', 'n'); ?> + get_exercice(); + if ($exercice == 0) { + alert(_('Aucune periode par defaut')); + } else { + $periode = new Periode($cn); + $limit = $periode->limit_year($exercice); + + $result = $rapport->get_row($limit['start'], $limit['end'], 'periode'); + $ix = 0; + if (!empty ($result) && count($result) > 0) { + echo ''; + foreach ($result as $row) { + $ix++; + $class = ($ix % 2 == 0) ? ' class="even" ' : ' class="odd" '; + echo ''; + + echo ''; + $style = 'style="text-align:right;"'; + if ($row['montant'] < 0) { + $style = 'style="color:red;text-align:right;"'; + } + echo ""; + echo ''; + } + echo '
      ' . $row['desc'] . '" . nbm($row['montant']) . "
      '; + } else { + echo _('Aucun résultat'); + } + } + } + $this->close_div(); + } + + /** + * @brief select the simple report (FORM_DEFINITION) to display + * @see Widget::make_form() + * @return void + */ + function input_parameter() { + + $select=new \ISelect('simple_report'); + $select->value=$this->db->make_array("select fr_id, fr_label from form_definition order by 2"); + + $this->make_form($select->input()); + } + + /** + * @brief Display the parameter of the form + * @return void + */ + function display_parameter() { + $aParam= $this->get_parameter(); + $name = $this->db->get_value("select fr_label from form_definition where fr_id=$1",[$aParam['simple_report']]); + echo " "; + echo span(_("Rapport") ." ".h($name),'class="widget_param"'); + + + } + +} \ No newline at end of file diff --git a/include/widget/todo_list/todo_list-display_new_note.php b/include/widget/todo_list/todo_list-display_new_note.php new file mode 100644 index 000000000..53cf5d337 --- /dev/null +++ b/include/widget/todo_list/todo_list-display_new_note.php @@ -0,0 +1,45 @@ + + diff --git a/include/widget/todo_list/todo_list.php b/include/widget/todo_list/todo_list.php new file mode 100644 index 000000000..e572c0f22 --- /dev/null +++ b/include/widget/todo_list/todo_list.php @@ -0,0 +1,77 @@ +'; + echo \HtmlInput::title_box(_('Pense-Bête'), "todo_listg_div", 'zoom', "zoom_todo()", 'n'); + echo \Dossier::hidden(); + $todo = new \Todo_List($cn); + $array = $todo->load_all(); + $a_todo = \Todo_List::to_object($cn, $array); + + echo \HtmlInput::button('add', _('Ajout'), 'onClick="add_todo()"', 'smallbutton'); + echo ''; + echo ''; + if (!empty ($array)) { + $nb = 0; + $today = date('d.m.Y'); + + foreach ($a_todo as $row) { + if ($nb % 2 == 0) $odd = 'odd '; else $odd = 'even '; + $nb++; + echo $row->display_row($odd); + } + } + echo '
      DateTitre
      '; + echo $this->display_new_note(); + echo ''; + } + + /************************************************************************** + * Ajout d'une nouvelle note + *************************************************************************/ + private function display_new_note() + { + require_once 'todo_list-display_new_note.php'; + } + +} + + diff --git a/include/widget/widget-development.md b/include/widget/widget-development.md new file mode 100644 index 000000000..f6c4756e8 --- /dev/null +++ b/include/widget/widget-development.md @@ -0,0 +1,108 @@ +# Développement de "widget" + +le code du widget , est toujours le même que celui du sous-répertoire dans NOALYSS_INCLUDE/widget, que le nom du fichier +principal et aussi, le nom de la CLASS. Donc ce nom ne peut pas contenir d'autres caractères que des lettres +et des soulignés. Toujours en minuscule. + +Il faut aussi l'ajouter dans la table WIDGET_DASHBOARD + * wd_id clef primaire + * wd_code code du widget + * wd_description description du widget , ce qu'il fait + * wd_parameter int , égal à 0, s'il n'y a pas de paramètre, à 1 s'il existe un paramètre (voir Paramètre) + +## Installation + +Création dans le répertoire d'un fichier appelé "install.php" dans le sous-répertoide qui sera exécuté si +le widget n'est pas encore dans la base de données + +Exemple + + global $cn; + + $cn->exec_sql("insert into widget_dashboard (wd_code,wd_description,wd_parameter,wd_name) values ($1,$2,$3,$4)", + array ( + 'event' + ,'Affiche les 10 actions en retards, celles à venir , les 10 prochaines factures client ou fournisseurs, ou celles en retard ' + ,1 + ,'10 actions ou factures' + ) + ); + + +## Ajax + +Tous les appels ajax appellent "html/ajax_misc.php" , la requête doit contenir : + + * la variable "op" : "widget" + * la variable "w" : chaine qui est le nom du widget (nom du sous-répertoire de include/widget) + +le fichier ajax.php du sous-répertoire NOALYSS_INCLUDE/widget/(w)/ajax.php sera appelé + +## Application + +La classe s'appele toujours "nom-du-widget.php" , elle est dérivée de widget et doit avoir les fonctions + +* display : affichage du widget +* input : affichage de la description et permet son activation (visible dans la box ) +* input-parameter : si des paramètres doivent être sauvées, les paramètres sont par utilisateurs et par widget activés, +* display_parameter + +### Paramètres + +Certains widgets peuvent être paramétrés, et il est possible d'ajouter plusieurs fois le même widget + +Exemple mini-report : choix du mini-report à afficher, + +Pour cela, il faut ajouter certaines fonctions : + +1. function input_parameter() : création d'un FORM dont le DOMID sera le code widget (wd_code) suivi de "_param" + +exemple pour mini_report + + function input_parameter() { + + $select=new \ISelect('simple_report'); + $select->value=$this->db->make_array("select fr_id, fr_label from form_definition order by 2"); + $this->make_form($select->input()); + } + +2. display_parameter : affichage du paramètre + +Les paramètres sont toujours sauvés "brut" , comme une chaîne URL, il faut donc pouvoir l'afficher, en la travaillant +avec parse_str, pour cela il faut appeler Widget->get_parameter(), le résultat doit être dans un SPAN avec la classe +"widget_param". + +Exemple pour mini_report + + function display_parameter() { + $aParam=$this->get_parameter(); + $name = $this->db->get_value("select fr_label from form_definition where fr_id=$1",[$aParam['simple_report']]); + echo " "; + echo span(_("Rapport") ." ".h($name),' class="widget_param"'); + + + } + + +### function display + +Toujours commencer par un DIV (id=code_widget+uw_id), Widget::open_div et Widget::close_div + +Exemple : + + $this->open_div(); + echo h2('Planifications','class="title"'); + // Code pour le widget + $this->open_div(); + +Voir aussi "Paramètres" + + +# Problèmes à résoudre + +## Taille + +Certains widget ont besoin de plus de place +Utilisation de vw et vh , attention agenda utilise des tailles fixes ! + +## Position diff --git a/include/widget/widget.php b/include/widget/widget.php new file mode 100644 index 000000000..d96d31e46 --- /dev/null +++ b/include/widget/widget.php @@ -0,0 +1,335 @@ +db=\Dossier::connect(); + } + } + + public function get_user_widget_id(): int + { + return $this->user_widget_id; + } + + public function set_user_widget_id(int $user_widget_id): Widget + { + $this->user_widget_id = $user_widget_id; + return $this; + } + + public function get_widget_code(): string + { + return $this->widget_code; + } + + public function set_widget_code(string $widget_code): Widget + { + $this->widget_code = $widget_code; + return $this; + } + + /** + * @brief display the content for the current connected user of the widget with the parameter + * @return mixed + */ + abstract function display(); + + /** + * @brief display a description of the widget and allow to save it for the current user, call input_param function + * of the widget if it exists + * @return mixed + */ + function input() + { + + //read description from database + $row=$this->db->get_row(" + select + wd_code + ,wd_name + ,wd_parameter, + wd_description + from + widget_dashboard + where + wd_code=$1", + [$this->widget_code]); + + echo "
    • user_widget_id}\"> {$row['wd_name']}{$row['wd_description']}"; + + if ( $this->user_widget_id > 0) { + if ( $row['wd_parameter'] == 1) { + $this->display_parameter(); + } + echo ''.\Icon_Action::trash(uniqid(),sprintf("widget.delete('%s')",$this->user_widget_id)); + } + else { + if ( $row['wd_parameter'] == 1) { + $this->input_parameter(); + } + echo ''.\Icon_Action::icon_add(uniqid(),sprintf("widget.add('%s')",$this->widget_code)); + } + + echo ''; + echo '
    • '; + } + + /** + * @brief returns an array of widget for the connected user, ordered + * @return array [ uw_id,dashboard_widget_id,wd_code,wd_description + */ + static function get_enabled_widget():array + { + global $g_user,$cn; + return $cn->get_array(" + select + uw.uw_id, + uw.dashboard_widget_id , + wd.wd_code, + wd.wd_description + from user_widget uw +join widget_dashboard wd on (uw.dashboard_widget_id=wd.wd_id) +where use_login=$1 order by uw.uw_order +",[$g_user->login]); + + } + + /** + * @brief Build a widget thank the user_widget_id (SQL :PK : USER_WIDGET.UW_ID) and $widget_code + * @param $user_widget_id integer (SQL :PK : USER_WIDGET.UW_ID) + * @param $widget_code string (SQL WIDGET_DASHBOARD.WD_CODE) + * @return Widget + */ + static function build_user_widget($user_widget_id,$widget_code):?Widget + { + // load the class if file (code/code.php) exists. + if (file_exists(NOALYSS_INCLUDE."/widget/$widget_code/$widget_code.php")) { + require_once NOALYSS_INCLUDE."/widget/$widget_code/$widget_code.php"; + $class=sprintf("\\Noalyss\\Widget\\%s",$widget_code); + $obj= new $class; + $obj->set_widget_code($widget_code); + $obj->set_user_widget_id($user_widget_id); + return $obj; + } + + // return the object + return null; + } + + /** + * @brief output the DIV HTML with class and id for the widget + * @return void + */ + function open_div() { + printf( '
      ',$this->widget_code,$this->user_widget_id); + } + function close_div() { + echo '
      '; + } + + /** + * @brief display a box and fills it with the content of an ajax calls , the ajax calls Widget::display + * @param Widget $widget + * @return void + */ + static function ajax_display(Widget $widget ){ + $box= sprintf( '%s_%s',$widget->get_widget_code(),$widget->get_user_widget_id()); + $widget->open_div(); + + print '
      '; + print '
      '; + print '
      '; + print '
      '; + print '
      '; + print '
      '; + print '
      '; + print '
      '; + echo p(_("Un instant, on charge :-)")); + $widget->close_div(); + + $dossier_id=\Dossier::id(); + echo << +var widget= new Widget('{$dossier_id}') +widget.display('{$box}',{$widget->get_user_widget_id()},'{$widget->get_widget_code()}') + + + +EOF; + + + + } + + /** + * @brier display activated widgets + * @return void + */ + static function display_available() + { + + $aWidget=Widget::get_enabled_widget(); + echo '
        '; + foreach ($aWidget as $item) { + $widget=Widget::build_user_widget($item['uw_id'],$item['wd_code']); + $widget->input(); + } + echo '
      '; + echo \HtmlInput::hidden("order_widget_hidden", ""); + create_script("widget.create_sortable()"); + } + + /** + * @brief save widget order from an array + * @param $array array of USER_WIDGET.UW_ID + * @return void + * @exception DatabaseCore fails , cannot update + */ + static function save($array) { + if (empty($array)) return; + global $cn,$g_user; + try { + $cn->start(); + $order=10; + $cn->exec_sql("create temporary table tmp_widget(user_widget_id integer,tw_order integer )"); + foreach ($array as $item) { + $cn->exec_sql('insert into tmp_widget(user_widget_id,tw_order ) values ($1,$2)', + [$item,$order]); + $order+=20; + } + $cn->exec_sql("delete from user_widget where use_login = $1 and uw_id not in (select user_widget_id from tmp_widget)", + array($g_user->getLogin())); + + $cn->exec_sql("update user_widget set uw_order =tw_order from tmp_widget where user_widget_id=uw_id"); + + $cn->commit(); + + } catch (\Exception $e) { + throw ($e); + } + + + } + + /** + * @brief show all the widget that can be added + * @return void + */ + public static function select_available() + { + global $cn; + Widget::scanfolder(); + $aWidget=$cn->get_array("select wd_code,wd_name, wd_description,wd_parameter from widget_dashboard order by wd_name"); + echo '
        '; + foreach ($aWidget as $item) { + $widget=Widget::build_user_widget(-1,$item['wd_code']); + $widget?->input(); + + } + echo '
      '; + } + + /** + * @brief open a form with the DOMID "widget_code"_param, it appears once only for each widget in the dialog box + * for adding widget to the dashboard + * @param $html_input string HTML string with all the HTML INPUT that will be enclosed by the FORM + * @return void + */ + function make_form($html_input) + { + printf ('
      ',$this->widget_code); + echo $html_input; + printf ('
      '); + } + + /** + * @brief MUST BE overrided if the widget needs extra parameters, create a FORM to add extra-parameter + * @return void + * @throws \Exception + */ + function input_parameter () + { + throw new \Exception(__FUNCTION__." not implemented"); + } + + /** + * @brief MUST BE overrided if the widget needs extra parameters, display the content of extra-parameter + * @param $user_widget_id + * @return void + * @throws \Exception + */ + + function display_parameter() { + throw new \Exception(__FUNCTION__." not implemented"); + } + + /** + * @brief scan folder to find install.php file , include them if the code is not in DB + * @return void + */ + static function scanfolder() + { + global $cn; + $handle=opendir(NOALYSS_INCLUDE."/widget"); + while (($dir = readdir($handle)) != false ) { + $directory=NOALYSS_INCLUDE."/widget".DIRECTORY_SEPARATOR.$dir; + if (is_dir($directory) && $dir != "." && $dir != "..") { + // code exists in DB ? + $cnt=$cn->get_value("select count(*) from widget_dashboard where wd_code = $1",[$dir]); + if ( $cnt > 0) { + continue; + } else { + // include the install.php file if any and install the widget + if (file_exists($directory . DIRECTORY_SEPARATOR . "install.php")){ + include $directory . DIRECTORY_SEPARATOR . "install.php"; + } + } + } + } + + } + + /** + * @brief get the parameter of the widget and returns an array + * @return array key=>value + */ + function get_parameter() + { + $param = $this->db->get_value("select uw_parameter from user_widget where uw_id=$1",[$this->user_widget_id]); + if (empty ($param)) return []; + parse_str($param,$aParam); + return $aParam; + } +} \ No newline at end of file diff --git a/sql/upgrade.sql b/sql/upgrade.sql index 8f116d3cf..605cce64b 100644 --- a/sql/upgrade.sql +++ b/sql/upgrade.sql @@ -21,3 +21,62 @@ select replace_menu_code('CFGTAG','C0TAG'); update menu_ref set me_description ='Configuration des extensions' where me_code='C0PLG'; update menu_ref set me_description ='Clef de répartition pour la comptabilité analytique' where me_code='ANCKEY'; + +--- widget pour DASHBOARD +drop table dashboard_widget; +drop table if exists user_widget; +drop table if exists user_widger; +drop table if exists widget_dashboard; + +create table widget_dashboard( + wd_id int primary key generated by default as identity, + wd_code text not null, + wd_description text not null, + wp_parameter int not null default 0 +); + + + +create table user_widget( + uw_id int primary key generated by default as identity, + use_login text not null, + dashboard_widget_id int not null references widget_dashboard(wd_id) on update cascade on delete cascade, + uw_parameter text , + uw_order int +); + +ALTER TABLE public.widget_dashboard RENAME COLUMN wp_parameter TO wd_parameter; +ALTER TABLE public.widget_dashboard ADD CONSTRAINT widget_dashboard_unique UNIQUE (wd_code); + +INSERT INTO public.widget_dashboard (wd_id,wd_code,wd_description,wd_parameter,wd_name) VALUES + (1,'agenda','Présentation d''un calendrier avec les dates de rappel des événements',0,'Agenda'), + (2,'todo_list','Liste de choses à faire , de petites notes',0,'Pense-Bête'), + (3,'coming_event','Rappel pour des actions pour aujourd''hui ou en retard',0,'Actions'), + (4,'last_operation','Affichage des dernières opérations comptables saisies',0,'Comptabilité'), + (5,'last_event','Affiche les derniers actions de suivi',0,'Suivi'), + (6,'mini_report','Affiche des rapports de comptabilité',1,'Rapport'); + + +INSERT INTO public.user_widget (use_login,dashboard_widget_id,uw_parameter,uw_order) + VALUES + ('admin',1,NULL,10), + ('admin',3,NULL,30), + ('admin',4,NULL,40), + ('admin',5,NULL,50), + ('admin',2,NULL,45); + +alter table public.widget_dashboard add wd_name text; +ALTER TABLE public.widget_dashboard ALTER COLUMN wd_name SET NOT NULL; + +ALTER TABLE public.widget_dashboard ALTER COLUMN wd_name SET NOT NULL; +COMMENT ON COLUMN public.widget_dashboard.wd_name IS 'Name'; +COMMENT ON COLUMN public.widget_dashboard.wd_id IS 'PK'; +COMMENT ON COLUMN public.widget_dashboard.wd_code IS 'Code'; +COMMENT ON COLUMN public.widget_dashboard.wd_description IS 'Description'; +COMMENT ON COLUMN public.widget_dashboard.wd_parameter IS 'presence of there is a parameter'; + +update menu_ref set me_menu = me_menu ||' 👤' where me_code='PREFERENCE'; +update menu_ref set me_menu = 'Impression 📊' where me_code='PRINT'; +update menu_ref set me_menu = me_menu || '📊' where me_code='RAPAV'; +update menu_ref set me_menu = me_menu ||' 📇' where me_code='CARD'; +update menu_ref set me_menu = 'Favori ✨' where me_code='BOOKMARK';