Webgui: user definable menu implemented

This commit is contained in:
2026-07-21 11:01:50 +02:00
parent 562aa587ad
commit a3d4825cbd
10 changed files with 490 additions and 300 deletions
+1
View File
@@ -22,6 +22,7 @@ INSERT INTO settings (userid, sno, valint) VALUES
INSERT INTO settings (userid, sno, valstr) VALUES INSERT INTO settings (userid, sno, valstr) VALUES
(-1, 1, 'vessel id'), (-1, 1, 'vessel id'),
(-1, 2, 'date format'), (-1, 2, 'date format'),
(-1, 3, 'user menu'),
(-1, 10, 'rows in table'), (-1, 10, 'rows in table'),
(-1, 20, 'maximum image width'), (-1, 20, 'maximum image width'),
(-1, 21, 'maximum image height'), (-1, 21, 'maximum image height'),
+83 -10
View File
@@ -235,6 +235,7 @@ class User {
public $vessel; // name of current vessel public $vessel; // name of current vessel
public $datefmt; public $datefmt;
public $rows_pp; public $rows_pp;
public $menu;
private function __construct() { private function __construct() {
global $g_rows_pp; global $g_rows_pp;
@@ -245,6 +246,7 @@ class User {
$this->vessel = 'Yacht'; $this->vessel = 'Yacht';
$this->datefmt = 'Y-m-d'; $this->datefmt = 'Y-m-d';
$this->rows_pp = $g_rows_pp; $this->rows_pp = $g_rows_pp;
$this->menu = [1, 2, 3, 4, 5, 6];
} }
public static function getInstance() { public static function getInstance() {
@@ -350,6 +352,18 @@ class User {
if ($user_rows_pp) { if ($user_rows_pp) {
$this->rows_pp = $user_rows_pp; $this->rows_pp = $user_rows_pp;
} }
// user defined menu
$sql = "SELECT valstr FROM settings WHERE userid=? AND sno=3";
$sth = $pdo->prepare($sql);
$sth->execute([$this->id]);
$res = $sth->fetchColumn();
if ($res === false) {
$sql = "INSERT INTO settings (userid, sno, valstr) VALUES (?, 3, ?)";
$sth = $pdo->prepare($sql);
$sth->execute([$this->id, implode(',', $this->menu)]);
} else {
$this->menu = array_map('intval', explode(',', $res));
}
} }
function get_last_error() { function get_last_error() {
@@ -1455,13 +1469,72 @@ function normalize_phone_e164($phone) {
// ========== MENU FUNCTIONS ================================================== // ========== MENU FUNCTIONS ==================================================
$g_menu = Array ( $g_modules = Array(
'equipment.php' => [_('Equipment')], 1 => ['file' => 'equipment.php',
'inventory.php' => [_('Inventory')], 'title' => _('Equipment'),
'provisions.php' => [_('Provisions')], 'type' => 'primary',
'maintenance.php' => [_('Maintenance')], 'group' => 'main'],
'projects.php' => [_('Projects')], 2 => ['file' => 'inventory.php',
'documents.php' => [_('Documents')], 'title' => _('Inventory'),
'manual.php' => ['<i class="bi-book"></i>'], 'type' => 'primary',
'logout.php' => ['<i class="bi-door-open"></i>'] 'group' => 'main'],
); 3 => ['file' => 'provisions.php',
'title' => _('Provisions'),
'type' => 'primary',
'group' => 'main'],
4 => ['file' => 'maintenance.php',
'title' => _('Maintenance'),
'type' => 'primary',
'group' => 'main'],
5 => ['file' => 'projects.php',
'title' => _('Projects'),
'type' => 'primary',
'group' => 'main'],
6 => ['file' => 'documents.php',
'title' => _('Documents'),
'type' => 'primary',
'group' => 'main'],
7 => ['file' => 'company.php',
'title' => _('Companies'),
'type' => 'primary',
'group' => 'base'],
8 => ['file' => 'task.php',
'title' => _('Task'),
'type' => 'primary',
'group' => 'extra'],
9 => ['file' => 'measurement.php',
'title' => _('Measurement'),
'type' => 'primary',
'group' => 'extra'],
10 => ['file' => 'storage.php',
'title' => _('Storage'),
'type' => 'primary',
'group' => 'base'],
11 => ['file' => 'box.php',
'title' => _('Boxes'),
'type' => 'primary',
'group' => 'extra'],
12 => ['file' => 'cable.php',
'title' => _('Cables'),
'type' => 'primary',
'group' => 'extra'],
13 => ['file' => 'fuse.php',
'title' => _('Fuses'),
'type' => 'primary',
'group' => 'extra'],
14 => ['file' => 'checklist.php',
'title' => _('Checklists'),
'type' => 'primary',
'group' => 'extra'],
15 => ['file' => 'tag.php',
'title' => _('Tags'),
'type' => 'secondary',
'group' => 'base'],
16 => ['file' => 'settings.php',
'title' => _('Settings'),
'type' => 'secondary',
'group' => 'extra'],
17 => ['file' => 'dropdown.php',
'title' => _('Selection lists'),
'type' => 'secondary',
'group' => 'base']);
+6 -3
View File
@@ -31,14 +31,17 @@ if (isset($GLOBALS['local_script'])) {
<div class="collapse navbar-collapse" id="navbarSupportedContent"> <div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav"> <ul class="navbar-nav">
<?php <?php
foreach ($g_menu as $key => $value) { for ($i = 0; $i < 6; $i++) {
echo str_repeat(' ', 4); echo str_repeat(' ', 4);
echo '<li class="nav-item">'; echo '<li class="nav-item">';
$active = ($g_scriptname == $key) ? ' active' : ''; $module = $g_modules[$user->menu[$i]];
echo '<a class="nav-link', $active,'" href="', $key, '">', $value[0], "</a>"; $active = ($g_scriptname == $module['file']) ? ' active' : '';;
echo '<a class="nav-link', $active,'" href="', $module['file'], '">', $module['title'], "</a>";
echo "</li>\n"; echo "</li>\n";
} }
?> ?>
<li class="nav-item"><a class="nav-link" href="manual.php"><i class="bi-book"></i></a></li>
<li class="nav-item"><a class="nav-link" href="logout.php"><i class="bi-door-open"></i></a></li>
</ul> </ul>
</div> </div>
</div> </div>
+22 -25
View File
@@ -8,6 +8,7 @@
require 'globals.inc'; require 'globals.inc';
require 'lib/gpc.inc'; require 'lib/gpc.inc';
require 'lib/svg.inc';
$pagetitle = _('Start'); $pagetitle = _('Start');
@@ -395,20 +396,26 @@ echo "</table>\n";
<div class="card-body"> <div class="card-body">
<h5 class="card-title"><?=_('Base data')?></h5> <h5 class="card-title"><?=_('Base data')?></h5>
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
<li class="list-group-item"><a href="dropdown.php"><?=_('Selection lists')?></a></li> <?php
<li class="list-group-item"><a href="tag.php"><?=_('Tags')?></a></li> // load all base modules not in main menu
<li class="list-group-item"><a href="storage.php"><?=_('Storage')?></a></li> foreach ($g_modules as $mid => $module) {
<li class="list-group-item"><a href="company.php"><?=_('Companies')?></a></li> if (!in_array($mid, $user->menu) && ($module['group'] === 'base')) {
echo ' <li class="list-group-item"><a href="', $module['file'], '">', $module['title'],"</a></li>\n";
}
}
?>
</ul> </ul>
<hr> <hr>
<h5 class="card-title"><?=_('Additional modules')?></h5> <h5 class="card-title"><?=_('Additional modules')?></h5>
<ul class="list-group list-group-flush"> <ul class="list-group list-group-flush">
<li class="list-group-item"><a href="settings.php"><?=_('Settings')?></a></li> <?php
<li class="list-group-item"><a href="task.php"><?=_('Tasks')?></a></li> // load all main or extra modules not in main menu
<li class="list-group-item"><a href="measurement.php"><?=_('Measurements')?></a></li> foreach ($g_modules as $mid => $module) {
<li class="list-group-item"><a href="cable.php"><?=_('Cables')?></a></li> if (!in_array($mid, $user->menu) && ($module['group'] === 'extra' || $module['group'] === 'main')) {
<li class="list-group-item"><a href="fuse.php"><?=_('Fuses')?></a></li> echo ' <li class="list-group-item"><a href="', $module['file'], '">', $module['title'],"</a></li>\n";
<li class="list-group-item"><a href="checklist.php"><?=_('Checklists')?></a></li> }
}
?>
</ul> </ul>
</div> </div>
</div> </div>
@@ -451,23 +458,12 @@ elseif ($action == ACT_EDIT):
// check if there is a shapefile-index // check if there is a shapefile-index
$shapeindexfile = $g_doc_basepath . '/shapeindex.json'; $shapeindexfile = $g_doc_basepath . '/shapeindex.json';
$shapeindex = [];
if (!file_exists($shapeindexfile)) { if (!file_exists($shapeindexfile)) {
// try to read metadata from top of svg file $shapeindex = create_shapeindex($shapeindexfile);
foreach (glob($g_shapedir.'/*.svg') as $f) {
$fh = fopen($f, 'r');
$fname = basename($f);
$header = fread($fh, 1024);
if (preg_match('/<title[^>]*>(.*?)<\/title>/is', $header, $match)) {
$title = trim($match[1]);
} else { } else {
$title = $fname; // check if shapeindex needs refresh (older than one day)
} if (time() - filemtime($shapeindexfile) > 86400) {
$shapeindex[$fname] = $title; $shapeindex = create_shapeindex($shapeindexfile);
fclose($fh);
}
$json = json_encode($shapeindex, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
file_put_contents($shapeindexfile, $json);
} else { } else {
// read svg metadata from existing file // read svg metadata from existing file
$json = file_get_contents($shapeindexfile); $json = file_get_contents($shapeindexfile);
@@ -477,6 +473,7 @@ if (!file_exists($shapeindexfile)) {
// perhaps regenerate index file? // perhaps regenerate index file?
} }
} }
}
$opt_shapefiles = $g_opt_none + $shapeindex; $opt_shapefiles = $g_opt_none + $shapeindex;
$opt_storage = db_get_opt_storage($user->vid); $opt_storage = db_get_opt_storage($user->vid);
+46 -5
View File
@@ -1,7 +1,7 @@
<?php <?php
/****************************************************************************** /******************************************************************************
* YMS - Yacht Management Software * YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge * Copyright (C) 2024-2026 Thomas Hooge
* *
* SPDX-License-Identifier: WTFPL * SPDX-License-Identifier: WTFPL
****************************************************************************** ******************************************************************************
@@ -10,8 +10,49 @@
// ========== SVG-FUNCTIONS =================================================== // ========== SVG-FUNCTIONS ===================================================
function svg_create_box($cx, $cy, $w, $h, $fg, $bg) { function create_shapeindex($shapeindexfile) {
// an existing index file will be overwritten
global $g_shapedir;
foreach (glob($g_shapedir.'/*.svg') as $f) {
$fh = fopen($f, 'r');
$fname = basename($f);
// try to read metadata from top of svg file
$header = fread($fh, 1024);
if (preg_match('/<title[^>]*>(.*?)<\/title>/is', $header, $match)) {
$title = trim($match[1]);
} else {
$title = $fname;
}
$shapeindex[$fname] = $title;
fclose($fh);
}
$json = json_encode($shapeindex, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
file_put_contents($shapeindexfile, $json);
return $shapeindex;
}
function get_shapeindex() {
global $g_doc_basepath;
$shapeindex = [];
$shapeindexfile = $g_doc_basepath . '/shapeindex.json';
if (!file_exists($shapeindexfile)) {
$shapeindex = create_shapeindex($shapeindexfile);
} else {
// check if shapeindex needs refresh (older than one day)
if (time() - filemtime($shapeindexfile) > 86400) {
$shapeindex = create_shapeindex($shapeindexfile);
} else {
// read svg metadata from existing file
$json = file_get_contents($shapeindexfile);
$shapeindex = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
// some kind of error: just recreate
$shapeindex = create_shapeindex($shapeindexfile);
}
}
}
return $shapeindex;
}
function svg_create_box($cx, $cy, $w, $h, $fg, $bg) {
} }
+287 -247
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+1 -1
View File
@@ -126,7 +126,7 @@ $sort = array(
$w = array('m.vid=:vid'); $w = array('m.vid=:vid');
$p = array(':vid' => $user->vid); $p = array(':vid' => $user->vid);
if ($flt->equip == -1 or $flt->equip == 0) { if (isset($flt->equip) and ($flt->equip == -1 or $flt->equip == 0)) {
$w[] = 'm.eid IS NULL'; $w[] = 'm.eid IS NULL';
} elseif ($flt->equip > 0) { } elseif ($flt->equip > 0) {
$w[] = 'm.eid=:eid'; $w[] = 'm.eid=:eid';
+16 -2
View File
@@ -72,6 +72,8 @@ switch ($submit = form_get_action()) {
$p[':projname'] = gpc_get_string($_POST, 'projname'); $p[':projname'] = gpc_get_string($_POST, 'projname');
$p[':startdate'] = gpc_get_date($_POST, 'startdate'); $p[':startdate'] = gpc_get_date($_POST, 'startdate');
$p[':duration'] = gpc_get_int($_POST, 'duration'); $p[':duration'] = gpc_get_int($_POST, 'duration');
$p[':costs_plan'] = gpc_get_currency($_POST, 'costs_plan');
$p[':costs_final'] = gpc_get_currency($_POST, 'costs_final');
$p[':projstate'] = gpc_get_string($_POST, 'projstate'); $p[':projstate'] = gpc_get_string($_POST, 'projstate');
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150); $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
db_exec_update('project', $p, 'projid'); db_exec_update('project', $p, 'projid');
@@ -296,7 +298,8 @@ form_create_select('responsible', _('Responsible'), $opt_user, $project->respons
elseif ($action == ACT_VIEW): elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record ===================================== // ========== VARIANT: view single record =====================================
$sql = "SELECT projname, startdate, duration, responsible, projstate, remarks " $sql = "SELECT projname, startdate, duration, responsible, projstate, "
. " costs_plan, costs_final, remarks "
. "FROM project " . "FROM project "
. "WHERE projid=?"; . "WHERE projid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -308,6 +311,8 @@ echo '<tr><th scope="row" style="width:20%">', _('Name'),"</th><td>", $project->
echo '<tr><th scope="row">', _('Responsible'),"</th><td>", $opt_user[$project->responsible], "</td></tr>\n"; echo '<tr><th scope="row">', _('Responsible'),"</th><td>", $opt_user[$project->responsible], "</td></tr>\n";
echo '<tr><th scope="row">', _('Start date'),"</th><td>", $project->startdate, "</td></tr>\n"; echo '<tr><th scope="row">', _('Start date'),"</th><td>", $project->startdate, "</td></tr>\n";
echo '<tr><th scope="row">', _('Duration'),"</th><td>", $project->duration, "</td></tr>\n"; echo '<tr><th scope="row">', _('Duration'),"</th><td>", $project->duration, "</td></tr>\n";
echo '<tr><th scope="row">', _('Costs plan'),"</th><td>", format_currency($project->costs_plan), "</td></tr>\n";
echo '<tr><th scope="row">', _('Costs final'),"</th><td>", format_currency($project->costs_final), "</td></tr>\n";
echo '<tr><th scope="row">', _('State'),"</th><td>", get_enum($project->projstate), "</td></tr>\n"; echo '<tr><th scope="row">', _('State'),"</th><td>", get_enum($project->projstate), "</td></tr>\n";
echo '<tr><th scope="row">', _('Remarks'),"</th><td>", nl2br($project->remarks), "</td></tr>\n"; echo '<tr><th scope="row">', _('Remarks'),"</th><td>", nl2br($project->remarks), "</td></tr>\n";
echo "</table>\n"; echo "</table>\n";
@@ -357,7 +362,8 @@ elseif ($action == ACT_EDIT):
echo '<h2>', _('Edit Project'), "</h2>\n"; echo '<h2>', _('Edit Project'), "</h2>\n";
$sql = "SELECT projname, responsible, startdate, duration, projstate, remarks " $sql = "SELECT projname, responsible, startdate, duration, projstate,"
. " costs_plan, costs_final, remarks "
. "FROM project " . "FROM project "
. "WHERE projid=?"; . "WHERE projid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -382,6 +388,14 @@ form_create_select('responsible', _('Responsible'), $opt_user, $project->respons
<label for="duration"><?=_('Duration, days')?></label> <label for="duration"><?=_('Duration, days')?></label>
<input type="number" class="form-control" id="duration" name="duration" min="1" value="<?=$project->duration ?>"> <input type="number" class="form-control" id="duration" name="duration" min="1" value="<?=$project->duration ?>">
</div> </div>
<div class="mb-3">
<label for="costs_plan" class="form-label"><?=sprintf(_('Costs planned, %s'), $g_lconv['currency_symbol']); ?></label>
<input type="text" class="form-control" id="costs_plan" name="costs_plan" value="<?=format_float($project->costs_plan) ?>">
</div>
<div class="mb-3">
<label for="costs_final" class="form-label"><?=sprintf(_('Costs final, %s'), $g_lconv['currency_symbol']); ?></label>
<input type="text" class="form-control" id="costs_final" name="costs_final" value="<?=format_float($project->costs_final) ?>">
</div>
<?php <?php
form_create_select('projstate', _('Status'), $opt_state, $project->projstate); form_create_select('projstate', _('Status'), $opt_state, $project->projstate);
?> ?>
+21
View File
@@ -39,6 +39,15 @@ switch ($submit = form_get_action()) {
$p[':valstr'] = NULL; $p[':valstr'] = NULL;
$p[':valint'] = gpc_get_int($_POST, 'rowspp'); $p[':valint'] = gpc_get_int($_POST, 'rowspp');
db_exec_update('settings', $p, $pk); db_exec_update('settings', $p, $pk);
$menu = [];
for ($i = 1; $i <= 6; $i++) {
$menu[] = gpc_get_uint($_POST, "menu$i", $i);
}
$p[':sno'] = 3; // user menu
$p[':valint'] = NULL;
$p[':valstr'] = implode(',', $menu);
db_exec_update('settings', $p, $pk);
$user->menu = $menu;
break; break;
default: default:
@@ -99,6 +108,18 @@ $maximgy = $pdo->query("SELECT valint FROM settings WHERE userid=0 AND sno=21")-
<form method="post" action="<?=$g_scriptname?>"> <form method="post" action="<?=$g_scriptname?>">
<h2><?=_('for current user')?></h2> <h2><?=_('for current user')?></h2>
<?php <?php
// menu configuration goes here
$opt_modules = [];
foreach ($g_modules as $mid => $module) {
if ($module['type'] === 'primary') {
$opt_modules[$mid] = $module['title'];
}
}
for ($i = 1; $i <= 6; $i++) {
form_create_select("menu$i", sprintf(_('Menu %d'), $i), $opt_modules, $user->menu[$i-1]);
}
form_create_select('datefmt', _('Date format'), $opt_datefmt, $datefmt); form_create_select('datefmt', _('Date format'), $opt_datefmt, $datefmt);
?> ?>
<div class="mb-3"> <div class="mb-3">