Added module historyDefault/getById to check current user in history.details.view + Refactor css + added info in svg tags + javascript began management (only launch event, implementation TODO)

This commit is contained in:
xdrm-brackets 2017-11-12 13:01:29 +01:00
parent b0f9cfae1e
commit 43e626d32d
6 changed files with 296 additions and 80 deletions

View File

@ -199,6 +199,39 @@
} }
/* (x) Return the entry data for an history id
*
* @id_entry<id> UID of the history entry
*
* @return data<array> Entry data
*
---------------------------------------------------------*/
public function getById($params){
extract($params);
/* (1) Get history entry data
---------------------------------------------------------*/
/* (1) Request */
$entry = new Repo('history/getById', [$id_entry]);
/* (2) Get response */
$entry = $entry->answer();
/* (3) Manage error */
if( !is_array($entry) )
return ['error' => new Error(Err::RepoError)];
/* (2) Return data
---------------------------------------------------------*/
return [ 'entry' => $entry ];
}
} }

View File

@ -11,6 +11,7 @@
public $id_history; public $id_history;
private $timeline = []; private $timeline = [];
private $entry = [];
/* (1) Constructor /* (1) Constructor
@ -23,7 +24,21 @@
---------------------------------------------------------*/ ---------------------------------------------------------*/
$this->id_history = $id_history; $this->id_history = $id_history;
/* (2) Get machine timeline
/* (3) Get entry data
---------------------------------------------------------*/
/* (1) Request */
$entry_req = new Request('historyDefault/getById', [ 'id_entry' => $this->id_history ]);
/* (2) Get response */
$entry_res = $entry_req->dispatch();
/* (3) On success, store entry data */
if( $entry_res->error->get() == Err::Success )
$this->entry = $entry_res->get('entry');
/* (3) Get machine timeline
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Request */ /* (1) Request */
$mac_req = new Request('historyDefault/get_timeline', [ 'id_entry' => $this->id_history ]); $mac_req = new Request('historyDefault/get_timeline', [ 'id_entry' => $this->id_history ]);
@ -61,68 +76,95 @@
$cl = count($this->timeline); $cl = count($this->timeline);
/* (4) Create ranges of size 15 */ /* (4) Create ranges of size 15 */
$r_size = 10; $r_size = 10; // set the number of actions by line
$rl = round( $cl / $r_size ); $rl = floor( $cl / $r_size ); // calculate the number of whole lines
$lrl = $cl % $r_size; // calculate the number of actions in the last line
$y_range_diff = 100; $y_range_diff = 100;
$total_height = $y_range_diff*$rl; $total_height = ($lrl == 0 ) ? $y_range_diff*$rl : $y_range_diff*($rl+1); // total height (number of entries + last if not empty)
/* (1) Svg tag */ /* (5) Svg tag */
$RAW .= "<svg width='1000' height='$total_height' viewBox='0 0 1000 $total_height'>"; $RAW .= "<svg width='1000' height='$total_height' viewBox='0 0 1000 $total_height' class='timeline'>";
/* (2) Start CIRCLE */ /* (6) Start CIRCLE */
$RAW .= "<circle cx='50' cy='50' r='6' fill='#edf0f5'/>"; $RAW .= "<circle cx='50' cy='50' r='6' fill='#edf0f5' class='tstart'/>";
$RAW .= "<circle cx='50' cy='50' r='4' fill='#555'/>"; $RAW .= "<circle cx='50' cy='50' r='4' fill='#555' class='tstart'/>";
for( $r = 0 ; $r < $rl ; $r++ ){ for( $r = 0 ; $r <= $rl ; $r++ ){
// if last line is empty -> stop here
if( $r == $rl && $lrl == 0 )
break;
$y = $y_range_diff*$r + 50; $y = $y_range_diff*$r + 50;
/* (2) Build barebone /* (2) Build barebone
---------------------------------------------------------*/ ---------------------------------------------------------*/
/* (1) Timeline LINE */ /* (1) Default TIMELINE */
$RAW .= "<path d='m50 $y L900 $y' style='stroke-dasharray: 3px;' stroke='#444'/>"; if( $r < $rl ){
$RAW .= "<path d='m50 $y L900 $y' style='stroke-dasharray: 3px;' stroke='#444' class='timeline line'/>";
/* (2) Last TIMELINE (can be shorter) */
}else{ // if last line -> trace timeline until last element +1
$len = 100 + $lrl*800/$r_size;
$RAW .= "<path d='m50 $y L$len $y' style='stroke-dasharray: 3px;' stroke='#444' class='timeline line'/>";
}
/* (3) Build each action /* (3) Build each action
---------------------------------------------------------*/ ---------------------------------------------------------*/
for( $c = 0 ; $c < $r_size ; $c++ ){ $el_len = ( $r == $rl ) ? $lrl : $r_size ;// number of elements on the line
for( $c = 0 ; $c < $el_len ; $c++ ){
// exit if no more entry /* (1) Display nothing if last entry and is empty */
if( !isset($this->timeline[$r*$r_size+$c]) ) if( !isset($this->timeline[$r*$r_size+$c]) )
break; break;
/* (2) Get entry data */
$entry = $this->timeline[$r*$r_size+$c]; $entry = $this->timeline[$r*$r_size+$c];
/* (3) Get useful data */
$action_class = strtolower($entry['action_name']); $action_class = strtolower($entry['action_name']);
$icon_uri = '/src/static/timeline/'.$action_class.'@'.$this->get_action_color($action_class).'.svg'; $icon_uri = '/src/static/timeline/'.$action_class.'@'.$this->get_action_color($action_class).'.svg';
$x_offset = 100 + $c*800/$r_size; $x_offset = 100 + $c*800/$r_size;
$x_img_offset = $x_offset - 5.5; $x_img_offset = $x_offset - 5.5;
$data_user = "data-user='".$entry['id_user']."'";
$data_machine = " data-machine='".$entry['id_machine']."'";
$data_action = " data-action='".$entry['id_action']."'";
$data_time = " data-time='".date('H:i:s d/m/Y', $entry['timestamp'])."'";
$data_tags = $data_user.$data_machine.$data_action.$data_time;
// circle /* (4) Draw entry circles */
$RAW .= "<circle cx='$x_offset' cy='$y' r='15' class='svg_$action_class op_svg'/>"; $RAW .= "<circle cx='$x_offset' cy='$y' r='15' class='timeline around $action_class' $data_tags />";
$RAW .= "<circle cx='$x_offset' cy='$y' r='12' class='svg_$action_class'/>"; $RAW .= "<circle cx='$x_offset' cy='$y' r='12' class='timeline center $action_class' />";
// inside icon /* (5) Draw circle around if not current user */
if( $this->entry['id_user'] != $entry['id_user'] )
$RAW .= "<circle cx='$x_offset' cy='$y' r='18' class='timeline user' />";
/* (6) Draw entry icon (action) */
$y_decal = $y - 5.5; $y_decal = $y - 5.5;
$RAW .= "<image x='$x_img_offset' y='$y_decal' width='12' height='12' xlink:href='$icon_uri'/>"; $RAW .= "\t<image x='$x_img_offset' y='$y_decal' width='12' height='12' xlink:href='$icon_uri' class='icon' />";
} }
// exit if no more entry
if( !isset($this->timeline[$r*$r_size]) )
break;
} }
/* (4) Stop CIRCLE */ /* (4) Close SVG
---------------------------------------------------------*/
/* (1) Stop CIRCLE */
$x_offset = 100 + $c*800/$r_size; $x_offset = 100 + $c*800/$r_size;
$RAW .= "<circle cx='$x_offset' cy='$y' r='6' fill='#edf0f5'/>"; $RAW .= "<circle cx='$x_offset' cy='$y' r='6' fill='#edf0f5' class='tstop' />";
$RAW .= "<circle cx='$x_offset' cy='$y' r='4' fill='#555'/>"; $RAW .= "<circle cx='$x_offset' cy='$y' r='4' fill='#555' class='tstop' />";
/* (5) Close SVG tag */ /* (2) Close SVG tag */
$RAW .= "</svg>"; $RAW .= "</svg>";

View File

@ -616,6 +616,17 @@
"output": { "output": {
"timeline": { "description": "Données de la timeline.", "type": "array" } "timeline": { "description": "Données de la timeline.", "type": "array" }
} }
},
"getById": {
"description": "Retourne les données associées à une entrée historique.",
"permissions": [["admin"]],
"parameters": {
"id_entry": { "description": "UID de l'entrée historique", "type": "id" }
},
"output": {
"entry": { "description": "Données de l'entrée.", "type": "array" }
}
} }
}, },

View File

@ -540,43 +540,83 @@ article.check-table{
/* [4] Timeline SVG /* [4] Timeline SVG
=========================================================*/ =========================================================*/
svg.timeline{
/* (1) svg circles -> set right transform-origin */ /* (1) svg circles -> set right transform-origin */
svg > circle[class^=svg_]{ & circle.timeline{
-webkit-transform-origin: 50% 50% 0; -webkit-transform-origin: 50% 50% 0;
transform-origin: 50% 50% 0; transform-origin: 50% 50% 0;
transition: transform .2s ease-in-out; transition: transform .2s ease-in-out;
}
/* (2) Set cursor to pointer */ /* (2) Set cursor to pointer */
svg > circle[class^=svg_]:not(.op_svg){ &.around{
cursor: pointer; cursor: pointer;
}
/* (3) Middle circles -> scale+ on hover */ /* (3) Dispatch event to next nodes */
svg > circle[class^=svg_]:not(.op_svg):hover{ &:hover + .center{ // center node
-webkit-transform: scale(1.2); -webkit-transform: scale(1.2);
transform: scale(1.2); transform: scale(1.2);
} }
/* (4) Avoid icons inside middle circles to block :hover */ &:hover + .center + .user{ // user node
svg > circle[class^=svg_]:not(.op_svg) + image{
-webkit-pionter-events: none; -webkit-transform: scale(.8);
transform: scale(.8);
}
}
/* (4) Remove center circle event */
&.center{
-webkit-pointer-events: none;
pointer-events: none; pointer-events: none;
} }
/* (5) Make around circles a bit transparent */ /* (5) Set colors according to action type */
svg > circle.op_svg{ &.around, &.center{
opacity: .6;
&.start{ fill: #2cde8b; }
&.stop{ fill: #3a3a3a; }
&.lock{ fill: #e04343; }
&.unlock{ fill: #af1c1c; }
&.signal{ fill: #3258d8; }
&.unsignal{ fill: #2041ab; }
} }
/* (6) Set circle colors according to action type */ /* (6) Make around circles a bit transparent */
svg > circle.svg_start{ fill: #2cde8b; } &.around{ opacity: .6; }
svg > circle.svg_stop{ fill: #3a3a3a; }
svg > circle.svg_lock{ fill: #e04343; } /* (7) User circles */
svg > circle.svg_unlock{ fill: #af1c1c; } &.user{
svg > circle.svg_signal{ fill: #3258d8; } fill: none;
svg > circle.svg_unsignal{ fill: #2041ab; } stroke-width: 1.5px;
stroke: #777;
stroke-opacity: .3;
}
/* (8) Set user colors according to action type */
&.center.start + .user{ stroke: #2cde8b; }
&.center.stop + .user{ stroke: #3a3a3a; }
&.center.lock + .user{ stroke: #e04343; }
&.center.unlock + .user{ stroke: #af1c1c; }
&.center.signal + .user{ stroke: #3258d8; }
&.center.unsignal + .user{ stroke: #2041ab; }
}
/* (9) Avoid icons inside center circles to block :hover */
image{
-webkit-pointer-events: none;
pointer-events: none;
}
}

View File

@ -698,59 +698,106 @@ article.check-table > div > span input[type='checkbox']:checked + label[for] {
/* [4] Timeline SVG /* [4] Timeline SVG
=========================================================*/ =========================================================*/
svg.timeline {
/* (1) svg circles -> set right transform-origin */ /* (1) svg circles -> set right transform-origin */
svg > circle[class^=svg_] { /* (9) Avoid icons inside center circles to block :hover */
}
svg.timeline circle.timeline {
-webkit-transform-origin: 50% 50% 0; -webkit-transform-origin: 50% 50% 0;
transform-origin: 50% 50% 0; transform-origin: 50% 50% 0;
transition: transform .2s ease-in-out; transition: transform .2s ease-in-out;
}
/* (2) Set cursor to pointer */ /* (2) Set cursor to pointer */
svg > circle[class^=svg_]:not(.op_svg) { /* (4) Remove center circle event */
cursor: pointer; /* (5) Set colors according to action type */
/* (6) Make around circles a bit transparent */
/* (7) User circles */
/* (8) Set user colors according to action type */
} }
/* (3) Middle circles -> scale+ on hover */ svg.timeline circle.timeline.around {
svg > circle[class^=svg_]:not(.op_svg):hover { cursor: pointer;
/* (3) Dispatch event to next nodes */
}
svg.timeline circle.timeline.around:hover + .center {
-webkit-transform: scale(1.2); -webkit-transform: scale(1.2);
transform: scale(1.2); transform: scale(1.2);
} }
/* (4) Avoid icons inside middle circles to block :hover */ svg.timeline circle.timeline.around:hover + .center + .user {
svg > circle[class^=svg_]:not(.op_svg) + image { -webkit-transform: scale(0.8);
-webkit-pionter-events: none; transform: scale(0.8);
}
svg.timeline circle.timeline.center {
-webkit-pointer-events: none;
pointer-events: none; pointer-events: none;
} }
/* (5) Make around circles a bit transparent */ svg.timeline circle.timeline.around.start, svg.timeline circle.timeline.center.start {
svg > circle.op_svg {
opacity: .6;
}
/* (6) Set circle colors according to action type */
svg > circle.svg_start {
fill: #2cde8b; fill: #2cde8b;
} }
svg > circle.svg_stop { svg.timeline circle.timeline.around.stop, svg.timeline circle.timeline.center.stop {
fill: #3a3a3a; fill: #3a3a3a;
} }
svg > circle.svg_lock { svg.timeline circle.timeline.around.lock, svg.timeline circle.timeline.center.lock {
fill: #e04343; fill: #e04343;
} }
svg > circle.svg_unlock { svg.timeline circle.timeline.around.unlock, svg.timeline circle.timeline.center.unlock {
fill: #af1c1c; fill: #af1c1c;
} }
svg > circle.svg_signal { svg.timeline circle.timeline.around.signal, svg.timeline circle.timeline.center.signal {
fill: #3258d8; fill: #3258d8;
} }
svg > circle.svg_unsignal { svg.timeline circle.timeline.around.unsignal, svg.timeline circle.timeline.center.unsignal {
fill: #2041ab; fill: #2041ab;
} }
svg.timeline circle.timeline.around {
opacity: .6;
}
svg.timeline circle.timeline.user {
fill: none;
stroke-width: 1.5px;
stroke: #777;
stroke-opacity: .3;
}
svg.timeline circle.timeline.center.start + .user {
stroke: #2cde8b;
}
svg.timeline circle.timeline.center.stop + .user {
stroke: #3a3a3a;
}
svg.timeline circle.timeline.center.lock + .user {
stroke: #e04343;
}
svg.timeline circle.timeline.center.unlock + .user {
stroke: #af1c1c;
}
svg.timeline circle.timeline.center.signal + .user {
stroke: #3258d8;
}
svg.timeline circle.timeline.center.unsignal + .user {
stroke: #2041ab;
}
svg.timeline image {
-webkit-pointer-events: none;
pointer-events: none;
}
/*# sourceMappingURL= container.css.map */ /*# sourceMappingURL= container.css.map */

View File

@ -151,3 +151,46 @@ if( section.archive.element != null ){
} }
/* GESTION DE L'AFFICHAGE DES DETAILS
*
*/
if( section.details.element != null ){
/* (1) Get useful DOM Elements
---------------------------------------------------------*/
section.details.event = {
// svg parent
parent: {
text: section.details.text+' svg ',
element: document.querySelector( section.details.text+' svg ' )
},
// each node
text: section.details.text+' svg circle.around ',
element: document.querySelectorAll( section.details.text+' svg circle.around ' )
};
/* (2) Function: show infobox on click on event
---------------------------------------------------------*/
section.details.event.handler = function(target){
console.log('show infobox on element', target);
};
/* (n) Trigger event */
section.details.event.parent.element.addEventListener('click', function(e){
// {1} Trigger function only if element is an 'around circle' //
if( e.target.nodeName && e.target.getData('user') && e.target.getData('machine') && e.target.getData('action') && e.target.getData('time') )
section.details.event.handler(e.target);
}, false);
}