User management with native gui and further improvements
@@ -15,6 +15,7 @@ Yacht Management Software (YMS) Installation
|
||||
- Python GTK3
|
||||
- python3-gi
|
||||
- gir1.2-gtk-3.0
|
||||
- gir-rsvg-2.0
|
||||
|
||||
1.3 Web GUI
|
||||
- Webserver
|
||||
@@ -69,7 +70,7 @@ Customize path and access rights to your needs
|
||||
To grant access for the local gui the directory has to be writeable by a special
|
||||
group (here as example 'yms'). The user which runs the local gui (here
|
||||
'guiuser') has also to be a member of that group as well as the webserver user
|
||||
''www-data'.
|
||||
'www-data'.
|
||||
|
||||
groupadd yms
|
||||
usermod -aG yms www-data
|
||||
@@ -107,14 +108,20 @@ Configfile should be readable by webserver but not writeable.
|
||||
Create a local database user with same name as your computer user and allow
|
||||
database acces with current unix credentials:
|
||||
mysql> CREATE USER 'ymsgui'@'localhost' IDENTIFIED VIA unix_socket;
|
||||
mysql> GRANT SELECT, INSERT, UPDATE, DELETE ON yms.* TO 'ymsgui'@'localhost';
|
||||
|
||||
Copy ymsgui.py to /usr/local/bin
|
||||
Copy directory yms to /usr/local/share
|
||||
|
||||
Start ymsgui.py, default configuration file is automatically created
|
||||
|
||||
7. Start using YMS
|
||||
|
||||
Use webgui:
|
||||
Start your browser and login to YMS with the default username/password:
|
||||
Start your browser and login to YMS with the initial username/password:
|
||||
captain/captain
|
||||
|
||||
Use local client:
|
||||
Start ymsgui.py
|
||||
Change the password using the local GUI before normal use.
|
||||
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
/* MariaDB Scheme
|
||||
Version: 1 */
|
||||
|
||||
/* TODO
|
||||
- check all values if unsigned can be used or not
|
||||
- implement foreign keys where possible
|
||||
- rename provisions to provision(?)
|
||||
*/
|
||||
|
||||
/* User
|
||||
userid is signed because nevative values are required for settings
|
||||
The user table must not be writeable by the webgui user!
|
||||
@@ -58,6 +64,28 @@ CREATE TABLE dropdown (
|
||||
PRIMARY KEY (ddid, ddval)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE company (
|
||||
compid smallint(6) NOT NULL AUTO_INCREMENT,
|
||||
compname varchar(60) NOT NULL,
|
||||
comptype tinyint(3) UNSIGNED NOT NULL DEFAULT 1,
|
||||
comptype2 tinyint(3) UNSIGNED DEFAULT NULL,
|
||||
shortname varchar(20) DEFAULT NULL,
|
||||
street varchar(40),
|
||||
zip varchar(10),
|
||||
city varchar(30),
|
||||
country varchar(30),
|
||||
contact varchar(30),
|
||||
phone varchar(30),
|
||||
email varchar(50),
|
||||
web varchar(40),
|
||||
customerno varchar(20),
|
||||
contractno varchar(20),
|
||||
remarks varchar(150) DEFAULT NULL,
|
||||
flags set('deleted','historic') DEFAULT NULL,
|
||||
PRIMARY KEY (compid),
|
||||
UNIQUE INDEX ix_compname (compname, comptype)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE vessel (
|
||||
vid smallint(6) NOT NULL AUTO_INCREMENT,
|
||||
vtype enum('mono','cat','tri') NOT NULL DEFAULT 'mono',
|
||||
@@ -76,14 +104,16 @@ CREATE TABLE vessel (
|
||||
shapefile varchar(40) DEFAULT NULL,
|
||||
sid_default smallint(6) UNSIGNED DEFAULT NULL, -- default storage
|
||||
remarks varchar(150) DEFAULT NULL,
|
||||
PRIMARY KEY (vid)
|
||||
PRIMARY KEY (vid),
|
||||
FOREIGN KEY fk_vessel_shipyard (shipyard)
|
||||
REFERENCES company(compid)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE storage (
|
||||
sid smallint(6) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
vid smallint(6) NOT NULL DEFAULT 1,
|
||||
sname varchar(40) NOT NULL,
|
||||
stype tinyint(3) NOT NULL DEFAULT 0,
|
||||
stype tinyint(3) NOT NULL DEFAULT 0, -- ddid=3
|
||||
capacity smallint(6) DEFAULT NULL,
|
||||
capaunit enum('kg','l') DEFAULT NULL,
|
||||
x smallint(6) UNSIGNED NOT NULL DEFAULT 0,
|
||||
@@ -148,6 +178,16 @@ CREATE TABLE equipment (
|
||||
PRIMARY KEY(eid)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
/*
|
||||
convert to
|
||||
sid SMALLINT UNSIGNED NULL,
|
||||
boxid SMALLINT UNSIGNED NULL,
|
||||
CHECK (
|
||||
(sid IS NOT NULL AND boxid IS NULL)
|
||||
OR
|
||||
(sid IS NULL AND boxid IS NOT NULL)
|
||||
)
|
||||
*/
|
||||
CREATE TABLE inventory (
|
||||
invid int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
invname varchar(80) NOT NULL,
|
||||
@@ -161,6 +201,7 @@ CREATE TABLE inventory (
|
||||
purchdate date DEFAULT NULL,
|
||||
invcond enum('unknown','excellent','good','fair','bad','repairable','defect') NOT NULL default 'unknown',
|
||||
remarks varchar(150) DEFAULT NULL,
|
||||
flags set('ordered','removed','deleted') DEFAULT NULL,
|
||||
PRIMARY KEY (invid),
|
||||
INDEX ix_invname (invname)
|
||||
) ENGINE=InnoDB;
|
||||
@@ -199,6 +240,7 @@ CREATE table fuse (
|
||||
UNIQUE INDEX ix_fusenumber (vid, fnumber)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
-- change vals to decimal(12,4)?
|
||||
CREATE TABLE measurement (
|
||||
mid smallint(6) NOT NULL AUTO_INCREMENT,
|
||||
mname varchar(80) NOT NULL,
|
||||
@@ -226,8 +268,10 @@ CREATE TABLE provisions (
|
||||
weight float(5,2) UNSIGNED DEFAULT NULL,
|
||||
weight_net float(5,2) UNSIGNED DEFAULT NULL,
|
||||
unit tinyint(3) DEFAULT NULL,
|
||||
calories smallint(6) UNSIGNED DEFAULT NULL,
|
||||
storedate date DEFAULT CURRENT_DATE,
|
||||
shelflife date DEFAULT NULL,
|
||||
price decimal(12,2) DEFAULT NULL,
|
||||
remarks varchar(150) DEFAULT NULL,
|
||||
PRIMARY KEY (provid)
|
||||
) ENGINE=InnoDB;
|
||||
@@ -259,38 +303,19 @@ CREATE TABLE docref (
|
||||
drid int(10) NOT NULL AUTO_INCREMENT,
|
||||
reftype enum('vessel','box','equipment','project','task','user','company') NOT NULL DEFAULT 'vessel',
|
||||
docid smallint(6) NOT NULL,
|
||||
refid smallint(6) NOT NULL,
|
||||
refid int(10) NOT NULL,
|
||||
PRIMARY KEY (drid),
|
||||
UNIQUE INDEX ix_docref (docid, refid),
|
||||
FOREIGN KEY fx_docref_doc (docid)
|
||||
UNIQUE INDEX ix_docref (docid, refid, reftype),
|
||||
FOREIGN KEY fk_docref_doc (docid)
|
||||
REFERENCES document (docid)
|
||||
ON DELETE RESTRICT
|
||||
ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE company (
|
||||
compid smallint(6) NOT NULL AUTO_INCREMENT,
|
||||
compname varchar(60) NOT NULL,
|
||||
comptype tinyint(3) UNSIGNED NOT NULL DEFAULT 1,
|
||||
comptype2 tinyint(3) UNSIGNED DEFAULT NULL,
|
||||
shortname varchar(20) DEFAULT NULL,
|
||||
street varchar(40),
|
||||
zip varchar(10),
|
||||
city varchar(30),
|
||||
country varchar(30),
|
||||
contact varchar(30),
|
||||
phone varchar(30),
|
||||
email varchar(50),
|
||||
web varchar(40),
|
||||
customerno varchar(20),
|
||||
contractno varchar(20),
|
||||
remarks varchar(150) DEFAULT NULL,
|
||||
flags set('deleted','historic') DEFAULT NULL,
|
||||
PRIMARY KEY (compid),
|
||||
UNIQUE INDEX ix_compname (compname, comptype)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
/* TODO optional field: plan date, target date, completion date */
|
||||
/* TODO optional fields: plan date, target date, completion date
|
||||
interval_hours, last_hours
|
||||
signalk: operating hours current vs maint every n operating hours in separate
|
||||
*/
|
||||
CREATE TABLE maintenance (
|
||||
maintid int(10) NOT NULL AUTO_INCREMENT,
|
||||
vid smallint(6) NOT NULL DEFAULT 1,
|
||||
@@ -332,14 +357,16 @@ CREATE TABLE task (
|
||||
finished datetime DEFAULT NULL,
|
||||
responsible smallint(6) NOT NULL,
|
||||
/* TODO executed_by : company or user? or both? */
|
||||
PRIMARY KEY (taskid)
|
||||
PRIMARY KEY (taskid),
|
||||
FOREIGN KEY fk_task_user (responsible)
|
||||
REFERENCES user(userid)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
/* Notes can be assigned to tasks,maintenances and equipment */
|
||||
CREATE TABLE note (
|
||||
noteid int(10) NOT NULL AUTO_INCREMENT,
|
||||
notetype enum('task','maint','equip') NOT NULL DEFAULT 'task',
|
||||
refid smallint(6) NOT NULL,
|
||||
refid int(10) NOT NULL,
|
||||
annotation text NOT NULL,
|
||||
PRIMARY KEY (noteid)
|
||||
) ENGINE=InnoDB;
|
||||
@@ -372,3 +399,16 @@ CREATE TABLE checkgroup (
|
||||
title varchar(30) NOT NULL,
|
||||
PRIMARY KEY (groupid)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
/* Expansion for future use: signalk mapping (just an idea) */
|
||||
CREATE TABLE signalk (
|
||||
skid int(10) NOT NULL AUTO_INCREMENT,
|
||||
vid smallint(6) NOT NULL,
|
||||
objtype enum('equipment','storage') NOT NULL,
|
||||
objid int(10) NOT NULL,
|
||||
datatype enum('engine_hours','tank_level') NOT NULL,
|
||||
skpath varchar(255) NOT NULL,
|
||||
PRIMARY KEY (skid),
|
||||
UNIQUE KEY ix_signalk
|
||||
(vid, objtype, objid, datatype)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
@@ -76,4 +76,5 @@ INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES
|
||||
|
||||
INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES
|
||||
(3, 0, 'Stauraum allgemein', 'fixed'),
|
||||
(3, 1, 'Tank', 'fixed');
|
||||
(3, 1, 'Tank', 'fixed'),
|
||||
(3, 2, 'Extern', 'fixed'); -- not on board
|
||||
|
||||
@@ -17,7 +17,7 @@ define('APP_ILLUSTRATION', 'sailboat.svg');
|
||||
|
||||
// database connection
|
||||
$g_db_host = 'localhost';
|
||||
$g_db_username = 'yms';
|
||||
$g_db_username = 'ymsweb';
|
||||
$g_db_password = 'changeme!';
|
||||
$g_db_schema = 'yms';
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ switch ($submit = form_get_action()) {
|
||||
// WIP New standalone document
|
||||
// debug $g_message->Add(print_r($_FILES, true));
|
||||
// check for possible errors
|
||||
// TODO use "noscale" option for images
|
||||
if (!isset($_FILES['files']['error']) || is_array($_FILES['files']['error'])) {
|
||||
$g_error->Add(_("Invalid file upload parameters."));
|
||||
$action = ACT_ADD;
|
||||
@@ -434,7 +435,7 @@ echo '<h2>', _('Add Document'), "</h2>\n";
|
||||
<label for="files" class="form-label"><?=_('Document')?></label>
|
||||
<input class="form-control" type="file" id="files" name="files" onchange="preview()">
|
||||
<img id="frame" src="" class="img-fluid">
|
||||
<button type="button" class="btn btn-secondary" onclick="clearimg();return false;"><?=_('Clear selection')?></button>
|
||||
<button type="button" class="btn btn-secondary mt-2" onclick="clearimg();return false;"><?=_('Clear selection')?></button>
|
||||
<script>
|
||||
function preview() {
|
||||
var images = ["image/png", "image/jpeg", "image/svg+xml"];
|
||||
@@ -451,6 +452,9 @@ echo '<h2>', _('Add Document'), "</h2>\n";
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
<?php
|
||||
form_create_check('noscale', _('Do not scale image'), FALSE);
|
||||
?>
|
||||
<div class="container-fluid px-0 my-3">
|
||||
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
|
||||
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
|
||||
|
||||
@@ -420,7 +420,7 @@ $flt = db_get_filter($user->id, 200);
|
||||
<input type="text" class="form-control" id="ename" name="ename">
|
||||
</div>
|
||||
<?php
|
||||
form_create_select('category', _('Category'), [-1 => '--- none ---'] + $opt_ecat, $flt->cat);
|
||||
form_create_select('category', _('Category'), $g_opt_none + $opt_ecat, $flt->cat);
|
||||
form_create_select('manufacturer', _('Manufacturer'), $opt_manufacturer, $flt->manuf);
|
||||
?>
|
||||
<div class="mb-3">
|
||||
|
||||
@@ -904,7 +904,8 @@ function db_get_opt_user($userid, $default=NULL) {
|
||||
return $list;
|
||||
}
|
||||
|
||||
function db_get_opt_proj($vid, $default=NULL) {
|
||||
function db_get_opt_proj($vid, $exclude=[], $default=NULL) {
|
||||
// exclude is a list of project states
|
||||
global $pdo;
|
||||
global $g_error;
|
||||
if (isset($default)) {
|
||||
@@ -912,7 +913,15 @@ function db_get_opt_proj($vid, $default=NULL) {
|
||||
} else {
|
||||
$list = array();
|
||||
}
|
||||
$sql = "SELECT projid, projname FROM project WHERE vid=? ORDER BY projname";
|
||||
$sql = "SELECT projid, projname FROM project WHERE vid=?";
|
||||
$where = [];
|
||||
foreach ($exclude as $excl) {
|
||||
$where[] = "NOT FIND_IN_SET('$excl',projstate)";
|
||||
}
|
||||
if (! empty($where)) {
|
||||
$sql .= ' AND '. implode(' AND ', $where);
|
||||
}
|
||||
$sql .= " ORDER BY projname";
|
||||
$sth = $pdo->prepare($sql);
|
||||
try {
|
||||
$sth->execute([$vid]);
|
||||
@@ -1047,6 +1056,18 @@ function form_create_text($fieldname, $label, $value) {
|
||||
echo "</div>\n";
|
||||
}
|
||||
|
||||
function form_create_check($fieldname, $label, $checked) {
|
||||
// create single checkbox with assigned label
|
||||
echo '<div class="mb-3">', "\n";
|
||||
echo '<input type="checkbox" class="form-check-input" name="', $fieldname, '" id="', $fieldname, '"';
|
||||
if ($checked) {
|
||||
echo ' checked';
|
||||
}
|
||||
echo ">\n";
|
||||
echo '<label for="', $fieldname, '">', $label, "</label>\n";
|
||||
echo "</div>\n";
|
||||
}
|
||||
|
||||
function form_create_select($fieldname, $label, $optlist, $selval=NULL, $multiple=FALSE) {
|
||||
echo '<div class="mb-3">', "\n";
|
||||
echo '<label for="', $fieldname, '">', $label, "</label>\n";
|
||||
@@ -1063,6 +1084,7 @@ function form_create_select($fieldname, $label, $optlist, $selval=NULL, $multipl
|
||||
}
|
||||
|
||||
function form_create_checks($fieldname, $label, $optlist, $selected = []) {
|
||||
// create multiple combined checkboxes with title
|
||||
echo '<fieldset class="mb-3">';
|
||||
echo '<legend class="fs-6 mb-1 border-bottom pb-1">', $label, "</legend>\n";
|
||||
echo '<div class="d-flex flex-wrap gap-3">';
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
let db;
|
||||
|
||||
const request = indexedDB.open("shopping", 1);
|
||||
|
||||
request.onupgradeneeded = function(event) {
|
||||
db = event.target.result;
|
||||
const store = db.createObjectStore(
|
||||
"items",
|
||||
{ keyPath: "provid" }
|
||||
);
|
||||
};
|
||||
|
||||
request.onsuccess = function(event) {
|
||||
db = event.target.result;
|
||||
checkDatabase();
|
||||
};
|
||||
|
||||
function checkDatabase()
|
||||
{
|
||||
let tx = db.transaction(
|
||||
"items",
|
||||
"readonly"
|
||||
);
|
||||
let store = tx.objectStore("items");
|
||||
let request = store.count();
|
||||
request.onsuccess = function(){
|
||||
if (request.result > 0) {
|
||||
renderLists();
|
||||
} else {
|
||||
importList(initialList);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function importList(list)
|
||||
{
|
||||
let tx = db.transaction(
|
||||
"items",
|
||||
"readwrite"
|
||||
);
|
||||
let store = tx.objectStore("items");
|
||||
list.forEach(item => {
|
||||
item.done = false;
|
||||
store.put(item);
|
||||
});
|
||||
tx.oncomplete = function(){
|
||||
renderLists();
|
||||
};
|
||||
}
|
||||
|
||||
function renderLists()
|
||||
{
|
||||
let tx = db.transaction(
|
||||
"items",
|
||||
"readonly"
|
||||
);
|
||||
let store = tx.objectStore("items");
|
||||
let request = store.getAll();
|
||||
request.onsuccess = function(){
|
||||
let pending = "";
|
||||
let completed = "";
|
||||
request.result.forEach(item => {
|
||||
let html = `
|
||||
<div class="item">
|
||||
<span class="name">
|
||||
${item.provname}
|
||||
</span>
|
||||
|
||||
<span>
|
||||
${item.buy} ${item.unit}
|
||||
</span>
|
||||
|
||||
<button onclick="completeItem(${item.provid})">
|
||||
✓
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
if (item.completed) {
|
||||
completed += html;
|
||||
} else {
|
||||
pending += html;
|
||||
}
|
||||
});
|
||||
document.getElementById("shoppingList").innerHTML = pending || "No items";
|
||||
document.getElementById("completedList").innerHTML = completed || "No completed items";
|
||||
};
|
||||
}
|
||||
|
||||
function plus(id)
|
||||
{
|
||||
let tx = db.transaction(
|
||||
"items",
|
||||
"readwrite"
|
||||
);
|
||||
let store = tx.objectStore("items");
|
||||
let req = store.get(id);
|
||||
req.onsuccess = function(){
|
||||
let item = req.result;
|
||||
item.buy++;
|
||||
store.put(item);
|
||||
renderLists();
|
||||
};
|
||||
}
|
||||
|
||||
function minus(id)
|
||||
{
|
||||
let tx = db.transaction(
|
||||
"items",
|
||||
"readwrite"
|
||||
);
|
||||
let store = tx.objectStore("items");
|
||||
let req = store.get(id);
|
||||
req.onsuccess = function(){
|
||||
let item = req.result;
|
||||
item.buy--;
|
||||
store.put(item);
|
||||
renderLists();
|
||||
};
|
||||
}
|
||||
|
||||
function completeItem(id)
|
||||
{
|
||||
let tx = db.transaction(
|
||||
"items",
|
||||
"readwrite"
|
||||
);
|
||||
let store = tx.objectStore("items");
|
||||
let request = store.get(id);
|
||||
request.onsuccess = function(){
|
||||
let item = request.result;
|
||||
item.completed = true;
|
||||
store.put(item);
|
||||
renderLists();
|
||||
};
|
||||
}
|
||||
|
||||
function undo(id)
|
||||
{
|
||||
let tx = db.transaction(
|
||||
"items",
|
||||
"readwrite"
|
||||
);
|
||||
let store = tx.objectStore("items");
|
||||
let req = store.get(id);
|
||||
req.onsuccess = function(){
|
||||
let item = req.result;
|
||||
item.done = false;
|
||||
store.put(item);
|
||||
showList();
|
||||
};
|
||||
}
|
||||
|
||||
function done(id)
|
||||
{
|
||||
let tx = db.transaction(
|
||||
"items",
|
||||
"readwrite"
|
||||
);
|
||||
let store = tx.objectStore("items");
|
||||
let req = store.get(id);
|
||||
req.onsuccess = function(){
|
||||
let item = req.result;
|
||||
item.done = true;
|
||||
store.put(item);
|
||||
showList();
|
||||
};
|
||||
}
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: YMS 0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-07-27 08:02+0200\n"
|
||||
"POT-Creation-Date: 2026-08-14 08:33+0200\n"
|
||||
"PO-Revision-Date: 2024-03-15 13:50+0100\n"
|
||||
"Last-Translator: Thomas Hooge <thomas@hoogi.de>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -16,7 +16,7 @@ msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
||||
#: box.php:19 index.php:353 globals.inc:1536
|
||||
#: box.php:19 index.php:357 globals.inc:1536
|
||||
msgid "Boxes"
|
||||
msgstr "Kisten"
|
||||
|
||||
@@ -48,7 +48,7 @@ msgid "Content"
|
||||
msgstr "Inhalt"
|
||||
|
||||
#: box.php:98 box.php:183 box.php:248 cable.php:211 equipment.php:464
|
||||
#: index.php:361 index.php:377 inventory.php:381 provisions.php:284
|
||||
#: index.php:365 index.php:381 inventory.php:384 provisions.php:284
|
||||
msgid "Weight"
|
||||
msgstr "Gewicht"
|
||||
|
||||
@@ -64,7 +64,7 @@ msgid "View"
|
||||
msgstr "Ansehen"
|
||||
|
||||
#: box.php:115 cable.php:151 company.php:231 documents.php:407 dropdown.php:162
|
||||
#: equipment.php:399 equipment_js.php:247 fuse.php:176 index.php:318
|
||||
#: equipment.php:399 equipment_js.php:247 fuse.php:176 index.php:322
|
||||
#: inventory.php:284 maintenance.php:197 maintenance.php:318
|
||||
#: measurement.php:235 projects.php:219 projects.php:264 projects.php:351
|
||||
#: provisions.php:219 storage.php:143 storage.php:182 tag.php:136 task.php:256
|
||||
@@ -77,7 +77,7 @@ msgid "Add Box"
|
||||
msgstr "Kiste hinzufügen"
|
||||
|
||||
#: box.php:138 box.php:184 box.php:311 inventory.php:208 inventory.php:313
|
||||
#: inventory.php:320 inventory.php:374 inventory.php:424 provisions.php:260
|
||||
#: inventory.php:320 inventory.php:374 inventory.php:427 provisions.php:260
|
||||
#: provisions.php:290 provisions.php:344 storage.php:12 storage.php:225
|
||||
#: globals.inc:564 globals.inc:1532
|
||||
msgid "Storage"
|
||||
@@ -87,7 +87,7 @@ msgstr "Stauraum"
|
||||
#: company.php:206 company.php:295 company.php:420 documents.php:430
|
||||
#: documents.php:538 documents.php:778 equipment.php:360 equipment.php:431
|
||||
#: equipment.php:469 equipment.php:684 equipment_js.php:69 fuse.php:237
|
||||
#: index.php:445 index.php:555 inventory.php:385 inventory.php:452
|
||||
#: index.php:449 index.php:559 inventory.php:388 inventory.php:455
|
||||
#: maintenance.php:180 maintenance.php:280 maintenance.php:350 projects.php:176
|
||||
#: projects.php:200 projects.php:290 projects.php:317 projects.php:403
|
||||
#: provisions.php:291 provisions.php:347 storage.php:122 storage.php:234
|
||||
@@ -97,7 +97,7 @@ msgstr "Bemerkungen"
|
||||
|
||||
#: box.php:156 company.php:255 company.php:427 documents.php:455
|
||||
#: documents.php:781 equipment.php:435 equipment.php:691 equipment_js.php:116
|
||||
#: equipment_js.php:283 index.php:449 inventory.php:324 maintenance.php:238
|
||||
#: equipment_js.php:283 index.php:453 inventory.php:324 maintenance.php:238
|
||||
#: measurement.php:284 note.php:158 projects.php:293 projects.php:406
|
||||
#: provisions.php:262 settings.php:146 storage.php:208 storage.php:363
|
||||
#: task.php:286 globals.inc:1112 globals.inc:1119
|
||||
@@ -107,7 +107,7 @@ msgstr "Speichern"
|
||||
#: box.php:157 company.php:256 company.php:428 company.php:454
|
||||
#: documents.php:456 documents.php:782 dropdown.php:214 dropdown.php:281
|
||||
#: equipment.php:436 equipment.php:692 equipment_js.php:117
|
||||
#: equipment_js.php:251 equipment_js.php:284 index.php:450 inventory.php:325
|
||||
#: equipment_js.php:251 equipment_js.php:284 index.php:454 inventory.php:325
|
||||
#: maintenance.php:239 measurement.php:285 note.php:159 projects.php:294
|
||||
#: projects.php:407 provisions.php:263 provisions.php:385 search.php:36
|
||||
#: settings.php:147 storage.php:209 storage.php:364 task.php:287
|
||||
@@ -139,12 +139,12 @@ msgstr "Keine verknüpften Bilder"
|
||||
msgid "Inventory in box"
|
||||
msgstr "Inventar in der Kiste"
|
||||
|
||||
#: box.php:246 index.php:375 inventory.php:12 search.php:80 globals.inc:1500
|
||||
#: box.php:246 index.php:379 inventory.php:12 search.php:80 globals.inc:1500
|
||||
msgid "Inventory"
|
||||
msgstr "Inventar"
|
||||
|
||||
#: box.php:247 dropdown.php:150 inventory.php:261 inventory.php:307
|
||||
#: inventory.php:380 inventory.php:414 provisions.php:183 provisions.php:248
|
||||
#: inventory.php:383 inventory.php:417 provisions.php:183 provisions.php:248
|
||||
#: provisions.php:282 provisions.php:316
|
||||
msgid "Number"
|
||||
msgstr "Anzahl"
|
||||
@@ -162,13 +162,13 @@ msgstr "― keine ―"
|
||||
msgid "Edit Box"
|
||||
msgstr "Kiste bearbeiten"
|
||||
|
||||
#: box.php:308 equipment.php:668 inventory.php:418 provisions.php:324
|
||||
#: box.php:308 equipment.php:668 inventory.php:421 provisions.php:324
|
||||
msgid "Weight, kg"
|
||||
msgstr "Gewicht, kg"
|
||||
|
||||
#: box.php:327 cable.php:298 checklist.php:170 company.php:465
|
||||
#: documents.php:815 dropdown.php:287 equipment.php:718 equipment_js.php:293
|
||||
#: fuse.php:290 index.php:566 inventory.php:480 maintenance.php:371
|
||||
#: fuse.php:290 index.php:570 inventory.php:483 maintenance.php:371
|
||||
#: measurement.php:369 note.php:226 projects.php:419 provisions.php:391
|
||||
#: settings.php:153 storage.php:390 tag.php:294 task.php:415
|
||||
msgid "Unknown function call: Please report to system development!"
|
||||
@@ -222,8 +222,8 @@ msgstr "Kabel"
|
||||
#: cable.php:127 cable.php:169 cable.php:235 checklist.php:153 company.php:204
|
||||
#: company.php:251 company.php:274 company.php:355 dropdown.php:185
|
||||
#: dropdown.php:233 equipment.php:419 equipment.php:651 equipment_js.php:101
|
||||
#: equipment_js.php:268 index.php:437 inventory.php:259 inventory.php:303
|
||||
#: inventory.php:410 measurement.php:256 measurement.php:303
|
||||
#: equipment_js.php:268 index.php:441 inventory.php:259 inventory.php:303
|
||||
#: inventory.php:413 measurement.php:256 measurement.php:303
|
||||
#: measurement.php:333 projects.php:169 projects.php:196 projects.php:245
|
||||
#: projects.php:283 projects.php:310 projects.php:377 provisions.php:244
|
||||
#: provisions.php:312 storage.php:120 storage.php:202 storage.php:316
|
||||
@@ -244,7 +244,7 @@ msgid "Cross section"
|
||||
msgstr "Querschnitt"
|
||||
|
||||
#: cable.php:132 cable.php:213 cable.php:266 inventory.php:222
|
||||
#: inventory.php:262 inventory.php:384 inventory.php:436
|
||||
#: inventory.php:262 inventory.php:387 inventory.php:439
|
||||
msgid "Condition"
|
||||
msgstr "Zustand"
|
||||
|
||||
@@ -429,7 +429,7 @@ msgstr "Stadt"
|
||||
msgid "Delete Company"
|
||||
msgstr "Firma löschen"
|
||||
|
||||
#: company.php:441 documents.php:802 equipment.php:707 inventory.php:470
|
||||
#: company.php:441 documents.php:802 equipment.php:707 inventory.php:473
|
||||
#: note.php:217 storage.php:379
|
||||
#, php-format
|
||||
msgid "Record no. %d"
|
||||
@@ -455,7 +455,7 @@ msgstr "Neuer GD Imagestream kann nicht initialisiert werden"
|
||||
msgid "Resource not found!"
|
||||
msgstr "Resource nicht gefunden!"
|
||||
|
||||
#: documents.php:21 index.php:381 task.php:343 globals.inc:1516
|
||||
#: documents.php:21 index.php:385 task.php:343 globals.inc:1516
|
||||
msgid "Documents"
|
||||
msgstr "Dokumente"
|
||||
|
||||
@@ -515,7 +515,7 @@ msgstr "SQL-Fehler: %s"
|
||||
msgid "Removed document reference"
|
||||
msgstr "Dokumentreferenz wurde entfernt"
|
||||
|
||||
#: documents.php:345 note.php:103
|
||||
#: documents.php:345 note.php:103 note.php:178
|
||||
msgid "Reference"
|
||||
msgstr "Referenz"
|
||||
|
||||
@@ -537,7 +537,7 @@ msgstr "Dokument"
|
||||
|
||||
#: documents.php:437
|
||||
msgid "Clear selection"
|
||||
msgstr "Auswah leeren"
|
||||
msgstr "Auswahl leeren"
|
||||
|
||||
#: documents.php:473
|
||||
msgid "View Document"
|
||||
@@ -597,14 +597,14 @@ msgid "Add new reference"
|
||||
msgstr "Neue Referenz hinzufügen"
|
||||
|
||||
#: documents.php:654 equipment.php:13 equipment_js.php:14 fuse.php:236
|
||||
#: index.php:359 inventory.php:450 maintenance.php:95 maintenance.php:179
|
||||
#: index.php:363 inventory.php:453 maintenance.php:95 maintenance.php:179
|
||||
#: maintenance.php:225 maintenance.php:274 maintenance.php:348
|
||||
#: measurement.php:281 measurement.php:312 measurement.php:358 search.php:52
|
||||
#: globals.inc:532 globals.inc:1496
|
||||
msgid "Equipment"
|
||||
msgstr "Ausrüstung"
|
||||
|
||||
#: documents.php:700 inventory.php:314 inventory.php:321 inventory.php:425
|
||||
#: documents.php:700 inventory.php:314 inventory.php:321 inventory.php:428
|
||||
#: storage.php:155 globals.inc:522
|
||||
msgid "Box"
|
||||
msgstr "Kiste"
|
||||
@@ -750,7 +750,7 @@ msgstr ""
|
||||
|
||||
#: equipment.php:357 equipment.php:427 equipment.php:462 equipment.php:660
|
||||
#: equipment_js.php:67 equipment_js.php:109 equipment_js.php:138
|
||||
#: equipment_js.php:276 index.php:441 index.php:505
|
||||
#: equipment_js.php:276 index.php:445 index.php:509
|
||||
msgid "Model"
|
||||
msgstr "Modell"
|
||||
|
||||
@@ -785,11 +785,11 @@ msgstr "Entfernt"
|
||||
msgid "Add Equipment"
|
||||
msgstr "Ausrüstung hinzufügen"
|
||||
|
||||
#: equipment.php:465 inventory.php:382
|
||||
#: equipment.php:465 inventory.php:385
|
||||
msgid "Price"
|
||||
msgstr "Preis"
|
||||
|
||||
#: equipment.php:466 equipment.php:676 inventory.php:383 inventory.php:432
|
||||
#: equipment.php:466 equipment.php:676 inventory.php:386 inventory.php:435
|
||||
msgid "Purchase date"
|
||||
msgstr "Kaufdatum"
|
||||
|
||||
@@ -841,7 +841,7 @@ msgstr "Keine Ersatzteile gefunden."
|
||||
msgid "Edit Equipment"
|
||||
msgstr "Ausrüstung bearbeiten"
|
||||
|
||||
#: equipment.php:672 inventory.php:428
|
||||
#: equipment.php:672 inventory.php:431
|
||||
#, php-format
|
||||
msgid "Price, %s"
|
||||
msgstr "Preis, %s"
|
||||
@@ -968,99 +968,99 @@ msgstr "Eigenbau"
|
||||
msgid "Built by %s"
|
||||
msgstr "Gebaut von %s"
|
||||
|
||||
#: index.php:303
|
||||
#: index.php:307
|
||||
msgid "Boat data"
|
||||
msgstr "Bootsdaten"
|
||||
|
||||
#: index.php:305
|
||||
#: index.php:309
|
||||
msgid "Loa"
|
||||
msgstr "LüA"
|
||||
|
||||
#: index.php:306
|
||||
#: index.php:310
|
||||
msgid "Lwl"
|
||||
msgstr "LWL"
|
||||
|
||||
#: index.php:307 index.php:517
|
||||
#: index.php:311 index.php:521
|
||||
msgid "Beam"
|
||||
msgstr "Breite"
|
||||
|
||||
#: index.php:308 index.php:521
|
||||
#: index.php:312 index.php:525
|
||||
msgid "Draught"
|
||||
msgstr "Tiefgang"
|
||||
|
||||
#: index.php:309 index.php:525
|
||||
#: index.php:313 index.php:529
|
||||
msgid "Draught, min."
|
||||
msgstr "Tiefgang, min."
|
||||
|
||||
#: index.php:310 index.php:529
|
||||
#: index.php:314 index.php:533
|
||||
msgid "Displacement"
|
||||
msgstr "Verdrängung"
|
||||
|
||||
#: index.php:311 index.php:533
|
||||
#: index.php:315 index.php:537
|
||||
msgid "Ballast"
|
||||
msgstr "Ballast"
|
||||
|
||||
#: index.php:312 index.php:537
|
||||
#: index.php:316 index.php:541
|
||||
msgid "Belt position aft"
|
||||
msgstr "Gurtposition achtern"
|
||||
|
||||
#: index.php:313 index.php:541
|
||||
#: index.php:317 index.php:545
|
||||
msgid "Belt position bow"
|
||||
msgstr "Gurtposition vorne"
|
||||
|
||||
#: index.php:329
|
||||
#: index.php:333
|
||||
msgid "Statistics"
|
||||
msgstr "Statistik"
|
||||
|
||||
#: index.php:345
|
||||
#: index.php:349
|
||||
msgid "Storage type"
|
||||
msgstr "Stauraumart"
|
||||
|
||||
#: index.php:360 index.php:376 index.php:382
|
||||
#: index.php:364 index.php:380 index.php:386
|
||||
msgid "Count"
|
||||
msgstr "Anzahl"
|
||||
|
||||
#: index.php:397
|
||||
#: index.php:401
|
||||
msgid "Base data"
|
||||
msgstr "Stammdaten"
|
||||
|
||||
#: index.php:409
|
||||
#: index.php:413
|
||||
msgid "Additional modules"
|
||||
msgstr "Zusatzmodule"
|
||||
|
||||
#: index.php:432
|
||||
#: index.php:436
|
||||
msgid "Add additional yacht"
|
||||
msgstr "Zusätzliche Yacht hinzufügen"
|
||||
|
||||
#: index.php:481
|
||||
#: index.php:485
|
||||
msgid "― Custom-built ―"
|
||||
msgstr "― Eigenbau ―"
|
||||
|
||||
#: index.php:497
|
||||
#: index.php:501
|
||||
msgid "Edit Yacht"
|
||||
msgstr "Yacht bearbeiten"
|
||||
|
||||
#: index.php:501
|
||||
#: index.php:505
|
||||
msgid "Vesselname"
|
||||
msgstr "Yachtname"
|
||||
|
||||
#: index.php:509
|
||||
#: index.php:513
|
||||
msgid "LoA"
|
||||
msgstr "LüA"
|
||||
|
||||
#: index.php:513
|
||||
#: index.php:517
|
||||
msgid "LwL"
|
||||
msgstr "LWL"
|
||||
|
||||
#: index.php:549
|
||||
#: index.php:553
|
||||
msgid "Shape file"
|
||||
msgstr "Rumpfform-Datei"
|
||||
|
||||
#: index.php:550
|
||||
#: index.php:554
|
||||
msgid "Shipyard"
|
||||
msgstr "Werft"
|
||||
|
||||
#: index.php:551
|
||||
#: index.php:555
|
||||
msgid "Default Storage"
|
||||
msgstr "Standard-Stauraum"
|
||||
|
||||
@@ -1085,7 +1085,7 @@ msgstr "Keine Tags zugeordnet"
|
||||
msgid "Add Inventory"
|
||||
msgstr "Inventar hinzufügen"
|
||||
|
||||
#: inventory.php:311 inventory.php:423
|
||||
#: inventory.php:311 inventory.php:426
|
||||
msgid "Container type"
|
||||
msgstr "Behälterart"
|
||||
|
||||
@@ -1094,19 +1094,23 @@ msgstr "Behälterart"
|
||||
msgid "%s in %s"
|
||||
msgstr ""
|
||||
|
||||
#: inventory.php:379
|
||||
#: inventory.php:378
|
||||
msgid "View Box"
|
||||
msgstr "Box ansehen"
|
||||
|
||||
#: inventory.php:382
|
||||
msgid "Location ID"
|
||||
msgstr "Position (x, y, z)"
|
||||
|
||||
#: inventory.php:406
|
||||
#: inventory.php:409
|
||||
msgid "Edit Inventory"
|
||||
msgstr "Inventar bearbeiten"
|
||||
|
||||
#: inventory.php:469
|
||||
#: inventory.php:472
|
||||
msgid "Delete Inventory"
|
||||
msgstr "Inventar löschen"
|
||||
|
||||
#: inventory.php:473
|
||||
#: inventory.php:476
|
||||
msgid ""
|
||||
"Deleting an inventory item is final. There is no way back. Only delete if "
|
||||
"you are absolute sure."
|
||||
@@ -1323,10 +1327,6 @@ msgstr "Notiz"
|
||||
msgid "View Note"
|
||||
msgstr "Notiz ansehen"
|
||||
|
||||
#: note.php:178
|
||||
msgid "Referenz"
|
||||
msgstr ""
|
||||
|
||||
#: note.php:196
|
||||
msgid "Edit Note"
|
||||
msgstr "Notiz bearbeiten"
|
||||
|
||||
@@ -75,6 +75,8 @@ Es wird das Einlagerungsdatum erfaßt und das Haltbarkeitsdatum</p>
|
||||
oder aber <em>frei</em>.
|
||||
Freier Proviant kann später zugeordnet
|
||||
werden. Er ist erkennbar am Einkaufswagen-Symbol <i class="bi bi-cart3"></i>.<p>
|
||||
<p>Proviant wird mit Brutto- und Nettogewicht geführt, hat einen Energiegehalt in kCal
|
||||
und ggf. einen Preis</p>
|
||||
|
||||
<p>TODO/Noch nichtimplementiert: Proviant kann auch in eine Kiste gelegt werden</p>
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ $note = $sth->fetch(PDO::FETCH_OBJ);
|
||||
// edit button
|
||||
// list where annotaion used
|
||||
echo '<table class="table">', "\n";
|
||||
echo '<tr><th>', _('Referenz'),"</th><td>", $note->refid, "</td></tr>\n";
|
||||
echo '<tr><th>', _('Reference'),"</th><td>", $note->refid, "</td></tr>\n";
|
||||
echo '<tr><th>', _('Type'),"</th><td>", $note->notetype, "</td></tr>\n";
|
||||
echo '<tr><th>', _('Annotation'),"</th><td>", nl2br($note->annotation), "</td></tr>\n";
|
||||
echo "</table>\n";
|
||||
|
||||
@@ -61,8 +61,10 @@ switch ($submit = form_get_action()) {
|
||||
$p[':weight'] = min(gpc_get_float($_POST, 'weight'), 999.99); // limit max value
|
||||
$p[':weight_net'] = min(gpc_get_float($_POST, 'weight_net'), 999.99);
|
||||
$p[':unit'] = gpc_get_int($_POST, 'unit');
|
||||
$p[':calories'] = gpc_get_uint($_POST, 'calories');
|
||||
$p[':storedate'] = gpc_get_string($_POST, 'storedate');
|
||||
$p[':shelflife'] = gpc_get_string($_POST, 'shelflife');
|
||||
$p[':price'] = gpc_get_currency($_POST, 'price');
|
||||
$p[':sid'] = gpc_get_int($_POST, 'sid');
|
||||
if ($p[':sid'] <= 0) $p[':sid'] = NULL;
|
||||
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
|
||||
@@ -269,7 +271,7 @@ elseif ($action == ACT_VIEW):
|
||||
// ========== VARIANT: view single record =====================================
|
||||
|
||||
$sql = "SELECT provname, provcat, number, target, unit, weight, weight_net,"
|
||||
. " storedate, shelflife, sid, remarks "
|
||||
. " calories, storedate, shelflife, price, sid, remarks "
|
||||
. "FROM provisions "
|
||||
. "WHERE provid=?";
|
||||
$sth = $pdo->prepare($sql);
|
||||
@@ -284,9 +286,11 @@ echo "<tr><th>", _('Target'), "</th><td>", $prov->target, "</td></tr>\n";
|
||||
echo "<tr><th>", _('Weight'), "</th><td>", format_float($prov->weight, 2, 'kg'), "</td></tr>\n";
|
||||
echo "<tr><th>", _('Weight net'), "</th><td>", format_float($prov->weight_net, 2, 'kg'), "</td></tr>\n";
|
||||
echo '<tr><th>', _('Unit'),"</th><td>", $opt_unit[$prov->unit], "</td></tr>\n";
|
||||
echo "<tr><th>", _('Calories'), "</th><td>", $prov->calories, " kcal</td></tr>\n";
|
||||
echo '<tr><th>', _('Category'),"</th><td>", $opt_category[$prov->provcat] ?? 'n/a', "</td></tr>\n";
|
||||
echo '<tr><th>', _('Storedate'),"</th><td>", $prov->storedate, "</td></tr>\n";
|
||||
echo '<tr><th>', _('Shelflife'),"</th><td>", $prov->shelflife, "</td></tr>\n";
|
||||
echo '<tr><th>', _('Price'), "</th><td>", format_currency($prov->price), "</td></tr>\n";
|
||||
echo '<tr><th>', _('Storage'),"</th><td>", ($opt_storage[$prov->sid] ?? ''), "</td></tr>\n";
|
||||
echo '<tr><th>', _('Remarks'),"</th><td>", nl2br($prov->remarks), "</td></tr>\n";
|
||||
echo "</table>\n";
|
||||
@@ -297,7 +301,7 @@ elseif ($action == ACT_EDIT):
|
||||
// ========== VARIANT: edit single record =====================================
|
||||
|
||||
$sql = "SELECT provname, provcat, number, target, unit, weight, weight_net,"
|
||||
. " storedate, shelflife, sid, remarks "
|
||||
. " calories, storedate, shelflife, price, sid, remarks "
|
||||
. "FROM provisions "
|
||||
. "WHERE provid=?";
|
||||
$sth = $pdo->prepare($sql);
|
||||
@@ -330,6 +334,12 @@ echo '<h2>', _('Edit provision'), "</h2>\n";
|
||||
</div>
|
||||
<?php
|
||||
form_create_select('unit', _('Unit'), $opt_unit, $prov->unit);
|
||||
?>
|
||||
<div class="mb-3">
|
||||
<label for="target"><?=_('Calories per Unit (kcal)')?></label>
|
||||
<input type="number" min="0" max="65000" class="form-control" id="calories" name="calories" value="<?=$prov->calories ?>">
|
||||
</div>
|
||||
<?php
|
||||
form_create_select('provcat', _('Category'), $g_opt_none + $opt_category, $prov->provcat);
|
||||
?>
|
||||
<div class="mb-3">
|
||||
@@ -340,6 +350,10 @@ form_create_select('provcat', _('Category'), $g_opt_none + $opt_category, $prov-
|
||||
<label for="shelflife"><?=_('Shelflife')?></label>
|
||||
<input type="date" class="form-control" id="shelflife" name="shelflife" value="<?=$prov->shelflife ?>">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="price" class="form-label"><?=sprintf(_('Price, %s'), $g_lconv['currency_symbol']); ?></label>
|
||||
<input type="text" class="form-control" id="price" name="price" value="<?=format_float($prov->price) ?>">
|
||||
</div>
|
||||
<?php
|
||||
form_create_select('sid', _('Storage'), $g_opt_none + $opt_storage, $prov->sid);
|
||||
?>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
style="display:inline"><path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.00001;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:8, 4, 2.00001, 4;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 42.346999,421.58603 H 1066.347"
|
||||
id="path399" /><path
|
||||
id="centerline" /><path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 43.434741,421.43502 c 0,0 0.413166,-22.42089 3.894359,-39.92496 8.859879,-44.54909 33.485118,-67.94835 93.87163,-87.80423 71.79884,-23.60841 231.35367,-47.44953 338.07331,-45.17591 58.4656,1.24559 128.71431,3.06837 239.1874,30.59247 125.0131,31.14672 271.98631,88.99119 345.78696,137.98517 0,0 0.7865,1.03131 0.972,1.63871 0.3052,0.99905 0.1801,3.12866 0.1801,3.12866"
|
||||
id="path1004" /><use
|
||||
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,138 @@
|
||||
<svg
|
||||
width="1024"
|
||||
height="325"
|
||||
viewBox="0 0 1024 325"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
xml:space="preserve"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><title
|
||||
id="title134">Colin Archer 40</title><defs
|
||||
id="defs2" /><g
|
||||
id="layer1"
|
||||
style="display:inline"><path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 32.902587,163.24723 c 0,0 -6.666293,-22.17724 51.732501,-67.565006 C 187.52515,15.715671 366.50013,5.7999235 433.65337,3.9666602 542.97458,0.98222366 704.13522,4.0275731 830.22893,58.523616 908.62334,92.40465 969.7182,149.13425 978.673,155.26415 c 5.4153,3.70695 4.5761,8.14666 4.5761,8.14666"
|
||||
id="path951" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path951"
|
||||
id="use1049"
|
||||
transform="matrix(1,0,0,-1,-0.05781152,326.36779)" /><path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 895.985,92.86984 V 232.55335"
|
||||
id="path1051" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 689.37014,17.637239 V 195.72401"
|
||||
id="path1051-36" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 540.10735,3.0789488 V 91.21857"
|
||||
id="path1051-36-7" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 690.02348,237.42732 V 307.8727"
|
||||
id="path1051-36-7-2" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 416.49715,4.2620683 V 132.78882"
|
||||
id="path1051-36-5" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 310.10943,14.105407 V 136.19705"
|
||||
id="path1051-36-3" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 113.52266,76.302173 V 251.83248"
|
||||
id="path1051-36-56" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 690.08485,105.08884 28.07694,0.60163"
|
||||
id="path1051-36-7-9" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 786.68796,42.130597 0.25367,46.194127 -16.3841,16.832756 -12.41255,0.48582"
|
||||
id="path1051-36-7-1" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 502.13905,196.92602 6.32096,0.0627 31.73427,26.11546 -0.69919,99.59481"
|
||||
id="path1051-36-7-27" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 417.82431,321.48565 0.004,-123.99946"
|
||||
id="path1051-36-7-0" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 308.66858,312.05474 0.81755,-70.25663"
|
||||
id="path1051-36-7-0-6" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 310.24697,200.53963 0.007,-13.8616"
|
||||
id="path1051-36-7-0-6-0" /><rect
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"
|
||||
id="rect625"
|
||||
width="152.16988"
|
||||
height="11.532784"
|
||||
x="866.78735"
|
||||
y="157.73856"
|
||||
rx="1.3628241"
|
||||
ry="1.3045897" /><rect
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect640"
|
||||
width="43.70451"
|
||||
height="5.1411266"
|
||||
x="2.7056627"
|
||||
y="160.75401"
|
||||
rx="1.3628241"
|
||||
ry="1.3045897" /><ellipse
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="path1248"
|
||||
cx="657.82275"
|
||||
cy="163.56593"
|
||||
rx="12.162697"
|
||||
ry="7.8855205" /><path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:8, 4, 2, 4;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 3.2714902e-6,163.30965 1024,163.3063"
|
||||
id="path271" /></g><g
|
||||
id="layer2"
|
||||
style="display:inline"
|
||||
transform="translate(-25.319896,5.562848)"><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 565.67989,236.15227 148.94077,0.58894"
|
||||
id="path1051-3" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 567.16163,86.445447 148.94077,0.58894"
|
||||
id="path1051-3-6" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 811.98823,83.068113 57.1816,30.733537 48.6489,-26.735129"
|
||||
id="path1051-3-2" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 854.02272,105.74204 876.63281,63.267145"
|
||||
id="path1051-3-2-6" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 715.48091,236.62096 39.15964,0.46197 -0.0963,57.26552"
|
||||
id="path1051-3-2-6-8" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 831.33681,93.198753 854.85906,52.701572"
|
||||
id="path1051-3-2-1" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 334.88168,257.06299 108.33469,-0.0336"
|
||||
id="path1051-3-7" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999994;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 335.54514,66.093576 106.51923,-0.0336"
|
||||
id="path1051-3-7-23" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 304.78037,14.051838 0.25341,67.943863 30.47429,-0.462178"
|
||||
id="path1051-3-7-9" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 248.70861,289.07127 14.00732,-51.92697 71.96665,5.09935"
|
||||
id="path1051-3-7-2" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 298.75245,239.75719 -7.2046,59.2492"
|
||||
id="path1051-3-7-0" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:0.99999899,1.99999797;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 444.22245,247.11088 63.11081,0.2124 13.52892,-40.80411 0.425,-100.58449 -13.78927,-39.435166 -65.58989,0.129781"
|
||||
id="path1051-3-7-7" /><rect
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:1, 2;stroke-dashoffset:0"
|
||||
id="rect1606"
|
||||
width="74.914055"
|
||||
height="69.12413"
|
||||
x="570.22064"
|
||||
y="122.47643"
|
||||
rx="1.3628241"
|
||||
ry="1.3045897" /></g><metadata
|
||||
id="metadata132"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:title>Colin Archer 40</dc:title><dc:creator><cc:Agent><dc:title>Thomas Hooge</dc:title></cc:Agent></dc:creator></cc:Work></rdf:RDF></metadata></svg>
|
||||
|
After Width: | Height: | Size: 9.2 KiB |
@@ -30,7 +30,7 @@
|
||||
<path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.268;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:1.072, 0.536, 0.268, 0.536;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 297.50974,51.957452 c -2.54837,0.522337 -297.50950858727,0 -297.50950858727,0"
|
||||
id="path857" />
|
||||
id="centerline" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.93889px;line-height:98%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
|
||||
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
@@ -28,7 +28,7 @@
|
||||
transform="matrix(1,0,0,-1,-0.02583644,109.41506)" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529169;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:2.11667, 1.05833, 0.529169, 1.05833;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 0.21617824,54.888403 270.69991,54.888402"
|
||||
id="path271" /><path
|
||||
id="centerline" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 141.00077,5.7751708 V 53.289576"
|
||||
id="path1051-5-20-3-5-3" /><path
|
||||
|
||||
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 8.7 KiB |
@@ -0,0 +1,289 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="1024"
|
||||
height="305"
|
||||
viewBox="0 0 1024 305"
|
||||
version="1.1"
|
||||
id="svg5"
|
||||
xml:space="preserve"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><title
|
||||
id="title134">Gulfstar 41</title><defs
|
||||
id="defs2" /><g
|
||||
id="layer1"
|
||||
style="display:inline"><path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:8, 4, 2, 4;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="M 3.3e-6,152.00334 1023.9982,151.99999"
|
||||
id="path271" /><path
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 4.541505,152.82638 c 0,0 0.729165,-54.491109 25.243635,-88.018502 C 94.775098,50.967238 140.69217,39.927662 199.55731,31.275058 297.4149,16.890941 397.62677,5.6293124 462.03098,4.859982 568.15897,3.5922467 688.37772,16.318765 809.42487,53.979712 912.75153,86.127351 1008.139,138.58129 1017.0525,144.71119 c 5.3903,3.70695 4.555,8.14666 4.555,8.14666"
|
||||
id="path951" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path951"
|
||||
id="use1049"
|
||||
transform="matrix(1,0,0,-1,0.14093269,304.94033)" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 296.62649,18.557857 V 286.46486"
|
||||
id="path1051-5" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 415.8873,227.21891 v 71.23063"
|
||||
id="path1051-5-20" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 296.3826,153.91187 75.74474,30.18682 72.23129,0.21079 -0.0479,-57.74576 -27.76098,-0.14802 -0.69918,-119.2298423"
|
||||
id="path1051-5-0" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 671.07416,20.286177 0.0415,128.557953 56.89431,-0.10936 29.62768,-23.18612 -0.78991,-85.78406"
|
||||
id="path1051-5-2-9" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 220.55901,28.151512 v 92.906228 l 17.65895,30.72635 58.41003,0.0579"
|
||||
id="path1051-7" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 296.53346,226.79659 -75.83471,-11.69391 -0.24255,61.15704"
|
||||
id="path1051-35" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 914.04719,93.338688 V 212.03375"
|
||||
id="path1051" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 755.60805,266.13836 -0.2572,-69.86532 -84.93468,-0.33711 -0.018,87.43233"
|
||||
id="path1051-5-2" /><ellipse
|
||||
style="display:inline;fill:none;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path1640"
|
||||
cx="594.63507"
|
||||
cy="152.02142"
|
||||
rx="8.7870979"
|
||||
ry="4.8806257" /></g><g
|
||||
id="layer2"
|
||||
style="display:inline"><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:1.99999, 0.999997;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 756.00672,238.37946 c 0,0 59.16733,-20.02492 85.38293,-30.44142 26.2156,-10.41649 71.66524,-31.86272 71.66524,-31.86272"
|
||||
id="path1051-3" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 669.46008,195.69652 508.5147,213.65213"
|
||||
id="path1051-3-9" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 822.22439,152.3697 758.17324,125.24424"
|
||||
id="path1051-3-9-62" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 822.09326,152.28781 -66.36093,29.18905 -0.0239,14.78286"
|
||||
id="path1051-3-9-62-6" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 508.55542,213.45397 0.0642,86.3025"
|
||||
id="path1051-3-9-97" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 670.76127,237.09813 508.69631,255.16318"
|
||||
id="path1051-3-9-75" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 670.66554,254.20123 508.64908,272.20918"
|
||||
id="path1051-3-9-92" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 661.4627,142.51176 -0.7724,-79.741048 c 0,0 -37.56032,-7.039363 -56.42139,-6.896387 -18.86107,0.142976 -55.78157,7.771263 -55.78157,7.771263 l -0.14541,79.791092"
|
||||
id="path1051-3-9-2" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 415.442,253.04762 295.11292,242.76125"
|
||||
id="path1051-3-9-7" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 460.1918,231.34815 -8.69345,-0.0532"
|
||||
id="path1051-3-9-9" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 416.39973,52.794624 297.21078,62.947673"
|
||||
id="path1051-3-9-6" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 296.55075,62.8079 -76.00147,0.07026"
|
||||
id="path1051-3-9-6-7" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 271.79139,151.82674 271.63843,63.050532"
|
||||
id="path1051-3-9-6-7-0" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 271.73415,111.91673 -51.28978,0.0489"
|
||||
id="path1051-3-9-6-7-0-9" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 671.34001,43.684548 541.56327,28.616168"
|
||||
id="path1051-3-9-6-1" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 670.65715,142.55208 -39.25248,0.44377 -1.31417,-55.619742 -48.91307,-0.79758 v 57.313592 l -40.07981,0.0484 L 540.4774,7.3776096"
|
||||
id="path1051-3-9-6-1-8" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:2, 0.999999;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 416.30812,74.92521 c 0,0 -82.47253,15.144404 -122.81009,25.9362 -40.33756,10.7918 -119.21527,38.81458 -119.21527,38.81458 l -0.48224,29.55534 c 0,0 80.54391,27.12128 120.73218,37.21131 40.18827,10.09004 121.27862,23.76758 121.27862,23.76758"
|
||||
id="path1051-3-7" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 219.67776,109.0587 93.855492,151.80189"
|
||||
id="path1051-3-7-3" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 219.86139,195.03714 94.039117,152.29395"
|
||||
id="path1051-3-7-3-6" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 220.0363,213.44097 219.71324,194.9243"
|
||||
id="path1051-3-7-3-6-6" /><use
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#path1051-6"
|
||||
id="use457"
|
||||
transform="matrix(1,0,0,-1,-0.13850787,304.9487)"
|
||||
style="display:inline" /><rect
|
||||
style="display:inline;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect1255"
|
||||
width="28.664709"
|
||||
height="25.4055"
|
||||
x="444.12122"
|
||||
y="150.14844" /><rect
|
||||
style="display:inline;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect1255-1"
|
||||
width="48.177208"
|
||||
height="62.083755"
|
||||
x="460.24216"
|
||||
y="224.74203" /><rect
|
||||
style="display:inline;fill:none;stroke:#000000;stroke-width:0.999998;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect1255-1-2"
|
||||
width="35.377628"
|
||||
height="52.031517"
|
||||
x="416.01917"
|
||||
y="228.25325" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 220.17782,38.804009 c 0,0 -56.08046,11.503545 -98.40722,29.919685 C 79.443836,87.139833 58.501345,112.47149 58.501345,112.47149 l -0.185798,40.1905"
|
||||
id="path1051-6" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 671.50207,60.229759 84.47664,0.731761"
|
||||
id="path1051-3-70" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 728.31329,60.955674 0.21143,87.895066"
|
||||
id="path1051-3-70-9" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999999;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 671.31947,114.80366 57.0344,0.0153"
|
||||
id="path1051-3-70-9-5" /><rect
|
||||
style="display:inline;fill:none;stroke:#000000;stroke-width:0.999995;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect1255-3"
|
||||
width="28.496277"
|
||||
height="25.182354"
|
||||
x="506.32599"
|
||||
y="47.019566" /><rect
|
||||
style="display:inline;fill:none;stroke:#000000;stroke-width:0.999995;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none"
|
||||
id="rect1255-3-6"
|
||||
width="40.192474"
|
||||
height="30.994183"
|
||||
x="453.94885"
|
||||
y="42.663792" /><circle
|
||||
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path1537"
|
||||
cx="473.59415"
|
||||
cy="50.722347"
|
||||
r="4.1049838" /><circle
|
||||
style="display:inline;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path1537-2"
|
||||
cx="484.03549"
|
||||
cy="64.60498"
|
||||
r="4.1049838" /><circle
|
||||
style="display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.999999;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path1537-2-3"
|
||||
cx="511.54593"
|
||||
cy="59.438629"
|
||||
r="1.4208409" /><circle
|
||||
style="display:inline;fill:none;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0"
|
||||
id="path1537-6"
|
||||
cx="463.9982"
|
||||
cy="64.60498"
|
||||
r="4.1049838" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 670.94118,54.557571 c 0,0 -43.64416,-7.676983 -65.60103,-7.709096 -21.95686,-0.03211 -65.08605,7.813561 -65.08605,7.813561"
|
||||
id="path1051-3-9-3" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 670.27867,245.85044 508.57702,264.03781"
|
||||
id="path1051-3-9-28" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 540.61416,41.075906 500.33278,41.27855 V 14.68724 h -51.75124 v 54.26063 l -32.33807,0.248933"
|
||||
id="path1051-3-9-36" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 541.01887,131.38337 -38.36889,-0.14689 0.35135,-55.159487 -58.43273,0.0059 0.12857,50.081065"
|
||||
id="path1051-3-9-1" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.999997;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 444.57231,76.176669 -0.002,-7.190214"
|
||||
id="path1051-3-9-29" /><rect
|
||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2020"
|
||||
width="22.906216"
|
||||
height="18.748451"
|
||||
x="507.5379"
|
||||
y="82.955887"
|
||||
ry="1.3045897"
|
||||
rx="1.3628241" /><rect
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2020-1"
|
||||
width="22.906216"
|
||||
height="18.748451"
|
||||
x="507.51715"
|
||||
y="106.56944"
|
||||
ry="1.3045897"
|
||||
rx="1.3628241" /><rect
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2020-1-3"
|
||||
width="12.380301"
|
||||
height="18.748451"
|
||||
x="276.67719"
|
||||
y="118.84782"
|
||||
ry="1.3045897"
|
||||
rx="1.3628241" /><rect
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2020-1-3-0"
|
||||
width="12.380301"
|
||||
height="18.748451"
|
||||
x="736.40729"
|
||||
y="103.76661"
|
||||
ry="1.3045897"
|
||||
rx="1.3628241" /><g
|
||||
id="g1346"
|
||||
transform="translate(1.6711347,1.1925367)"><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 711.61753,105.88116 2.65465,-0.01"
|
||||
id="path1051-3-70-9-6" /><rect
|
||||
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2591-3"
|
||||
width="8.0729084"
|
||||
height="10.706293"
|
||||
x="714.31329"
|
||||
y="101.32455"
|
||||
ry="0" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 716.92538,107.04318 2.79647,-0.003"
|
||||
id="path1051-3-70-9-6-7" /><path
|
||||
id="rect2588"
|
||||
style="fill:#ffffff;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;fill-opacity:1"
|
||||
d="m 686.24942,90.899539 20.82037,0.08492 c 0,0 5.06651,8.402799 4.39879,16.424111 -0.93076,11.18123 -8.47355,16.69152 -14.7092,16.79516 -6.23564,0.1036 -13.73785,-6.42007 -14.55567,-15.91907 -0.83507,-9.699525 4.04571,-17.385082 4.04571,-17.385082 z" /><rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2591"
|
||||
width="22.45204"
|
||||
height="2.0430894"
|
||||
x="685.52374"
|
||||
y="88.79052" /></g><g
|
||||
id="g1346-5"
|
||||
transform="translate(-452.44821,-6.2064984)"
|
||||
style="display:inline"><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 711.61753,105.88116 2.65465,-0.01"
|
||||
id="path1051-3-70-9-6-6" /><rect
|
||||
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2591-3-2"
|
||||
width="8.0729084"
|
||||
height="10.706293"
|
||||
x="714.31329"
|
||||
y="101.32455"
|
||||
ry="0" /><path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 716.92538,107.04318 2.79647,-0.003"
|
||||
id="path1051-3-70-9-6-7-9" /><path
|
||||
id="rect2588-1"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round"
|
||||
d="m 686.24942,90.899539 20.82037,0.08492 c 0,0 5.06651,8.402799 4.39879,16.424111 -0.93076,11.18123 -8.47355,16.69152 -14.7092,16.79516 -6.23564,0.1036 -13.73785,-6.42007 -14.55567,-15.91907 -0.83507,-9.699525 4.04571,-17.385082 4.04571,-17.385082 z" /><rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2591-2"
|
||||
width="22.45204"
|
||||
height="2.0430894"
|
||||
x="685.52374"
|
||||
y="88.79052" /></g></g><metadata
|
||||
id="metadata132"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:title>Shape template</dc:title><dc:creator><cc:Agent><dc:title>Thomas Hooge</dc:title></cc:Agent></dc:creator></cc:Work></rdf:RDF></metadata></svg>
|
||||
|
After Width: | Height: | Size: 20 KiB |
@@ -13,7 +13,7 @@ $pagetitle = _('Task');
|
||||
|
||||
$id = gpc_get_int($_REQUEST, 'id', 0);
|
||||
|
||||
$opt_projects = db_get_opt_proj($user->vid, array(-1 => _('unassigned')));
|
||||
$opt_projects = db_get_opt_proj($user->vid, [], array(-1 => _('unassigned')));
|
||||
$opt_priority = db_load_enum('task', 'priority', true, true);
|
||||
$opt_state = db_load_enum('task', 'taskstate', true, true);
|
||||
|
||||
@@ -30,6 +30,7 @@ switch ($submit = form_get_action()) {
|
||||
|
||||
case 'filter':
|
||||
$flt = array();
|
||||
$flt['proj'] = gpc_get_int($_POST, 'flt_proj');
|
||||
$flt['prio'] = gpc_get_enum($_POST, 'flt_prio', array_merge(array_keys($opt_priority), ['-2', '-1']));
|
||||
$flt['txt'] = gpc_get_string($_POST, 'flt_txt');
|
||||
$allowed = db_load_enum('task', 'taskstate');
|
||||
@@ -125,7 +126,7 @@ if ($action == ACT_DEFAULT):
|
||||
page_caption_search($pagetitle);
|
||||
|
||||
// load filter from db
|
||||
$flt = db_get_filter($user->id, 206, ['txt','prio', 'stat']);
|
||||
$flt = db_get_filter($user->id, 206, ['txt', 'prio', 'stat', 'proj']);
|
||||
|
||||
$w = array('(t.vid=:vid OR t.vid IS NULL)');
|
||||
$p = array(':vid' => $user->vid);
|
||||
@@ -133,16 +134,18 @@ if (strlen($flt->txt) > 1) {
|
||||
$w[] = '(taskname LIKE :txt)';
|
||||
$p[':txt'] = '%'.$flt->txt.'%';
|
||||
}
|
||||
if ($flt->proj > 0) {
|
||||
$w[] = 'projid=:projid';
|
||||
$p[':projid'] = $flt->proj;
|
||||
} elseif ($flt->proj == -1) {
|
||||
$w[] = 'projid IS NULL';
|
||||
}
|
||||
if (strlen($flt->prio) > 2 ) {
|
||||
$w[] = 'priority=:priority';
|
||||
$p[':priority'] = $flt->prio;
|
||||
} elseif ($flt->prio == -1) {
|
||||
$w[] = 'priority IS NULL';
|
||||
}
|
||||
/*if (strlen($flt->stat) > 2 ) {
|
||||
$w[] = 'taskstate=:taskstate';
|
||||
$p[':taskstate'] = $flt->stat;
|
||||
} */
|
||||
$parts = ["taskstate=''", 'taskstate IS NULL'];
|
||||
foreach ($flt->stat as $f) {
|
||||
$parts[] = "FIND_IN_SET('$f', taskstate)";
|
||||
@@ -202,8 +205,9 @@ $res = $sth->fetchAll();
|
||||
<div class="card-header"><i class="bi bi-funnel me-2"></i>Filter</div>
|
||||
<div class="card-body d-flex flex-wrap gap-3">
|
||||
<?php
|
||||
$opt_proj_filter = db_get_opt_proj($user->vid, ['finished']);
|
||||
filter_create_select('flt_proj', _('Project'), $g_opt_all + $g_opt_none + $opt_proj_filter, $flt->proj);
|
||||
filter_create_select('flt_prio', _('Priority'), $g_opt_all + $g_opt_none + $opt_priority, $flt->prio);
|
||||
//filter_create_select('flt_stat', _('State'), $g_opt_all + $opt_state, $flt->stat);
|
||||
?>
|
||||
<div class="d-flex flex-nowrap gap-2">
|
||||
<label for="flt_txt">Text</label>
|
||||
|
||||
@@ -163,26 +163,25 @@
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="lvw_user">
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkSeparator">
|
||||
<object class="GtkTreeView" id="tvw_user">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="can-focus">True</property>
|
||||
<signal name="row-activated" handler="on_tvw_user_row_activated" swapped="no"/>
|
||||
<child internal-child="selection">
|
||||
<object class="GtkTreeSelection"/>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
@@ -191,11 +190,12 @@
|
||||
<property name="can-focus">False</property>
|
||||
<property name="layout-style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkButton" id="but_user_new">
|
||||
<property name="label" translatable="yes">New</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<signal name="clicked" handler="on_but_user_new_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
@@ -204,11 +204,12 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkButton" id="but_user_del">
|
||||
<property name="label" translatable="yes">Delete</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<signal name="clicked" handler="on_but_user_del_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
@@ -220,7 +221,7 @@
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
@@ -262,7 +263,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry">
|
||||
<object class="GtkEntry" id="ent_user_login">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
</object>
|
||||
@@ -272,7 +273,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry">
|
||||
<object class="GtkEntry" id="ent_user_displayname">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
</object>
|
||||
@@ -304,7 +305,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox">
|
||||
<object class="GtkComboBox" id="cmb_user_role">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
@@ -314,7 +315,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBox">
|
||||
<object class="GtkComboBox" id="cmb_user_lang">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
</object>
|
||||
@@ -335,7 +336,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry">
|
||||
<object class="GtkEntry" id="ent_user_pass">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
</object>
|
||||
@@ -345,11 +346,12 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkButton" id="but_user_newpass">
|
||||
<property name="label" translatable="yes">Create</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<signal name="clicked" handler="on_but_user_newpass_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left-attach">2</property>
|
||||
@@ -357,7 +359,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton">
|
||||
<object class="GtkCheckButton" id="chk_user_locked">
|
||||
<property name="label" translatable="yes">Locked</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
@@ -370,7 +372,7 @@
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkCheckButton">
|
||||
<object class="GtkCheckButton" id="chk_user_deleted">
|
||||
<property name="label" translatable="yes">Deleted</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
@@ -446,11 +448,12 @@
|
||||
<property name="can-focus">False</property>
|
||||
<property name="layout-style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<object class="GtkButton" id="but_user_save">
|
||||
<property name="label" translatable="yes">Save</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<property name="receives-default">True</property>
|
||||
<signal name="clicked" handler="on_but_user_save_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
@@ -480,7 +483,7 @@
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">Lists</property>
|
||||
<property name="label" translatable="yes">User</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
@@ -560,7 +563,7 @@
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">False</property>
|
||||
<property name="label" translatable="yes">User</property>
|
||||
<property name="label" translatable="yes">Lists</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="position">2</property>
|
||||
@@ -846,7 +849,7 @@
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView">
|
||||
<object class="GtkTreeView" id="tvw_equipment">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<child internal-child="selection">
|
||||
@@ -1831,7 +1834,7 @@
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView">
|
||||
<object class="GtkTreeView" id="tvw_provisions">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<child internal-child="selection">
|
||||
@@ -2040,7 +2043,7 @@
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView">
|
||||
<object class="GtkTreeView" id="tvw_maintenance">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<child internal-child="selection">
|
||||
@@ -2270,7 +2273,7 @@
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView">
|
||||
<object class="GtkTreeView" id="tvw_projects">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<child internal-child="selection">
|
||||
@@ -2500,7 +2503,7 @@
|
||||
<property name="can-focus">True</property>
|
||||
<property name="shadow-type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView">
|
||||
<object class="GtkTreeView" id="tvw_documents">
|
||||
<property name="visible">True</property>
|
||||
<property name="can-focus">True</property>
|
||||
<child internal-child="selection">
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import MySQLdb.cursors
|
||||
import bcrypt
|
||||
import random
|
||||
import string
|
||||
|
||||
class User(object):
|
||||
|
||||
@classmethod
|
||||
def genpass(cls, length=12):
|
||||
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
|
||||
|
||||
def __init__(self, dbconn, user_id=None):
|
||||
self.conn = dbconn
|
||||
self.cur = dbconn.cursor(MySQLdb.cursors.DictCursor)
|
||||
if user_id:
|
||||
if user_id is not None:
|
||||
self.user_id = int(user_id)
|
||||
self.load()
|
||||
else:
|
||||
@@ -15,13 +22,13 @@ class User(object):
|
||||
self.displayname = None
|
||||
self.language = 'en'
|
||||
self.role = 'undef'
|
||||
self.flags = ''
|
||||
self.flags = []
|
||||
|
||||
def load(self):
|
||||
def load(self, user_id=0):
|
||||
sql = (
|
||||
"SELECT login, displayname, language, role, flags "
|
||||
"FROM user "
|
||||
"WHERE user_id=%s")
|
||||
"WHERE userid=%s")
|
||||
self.cur.execute(sql, (self.user_id, ))
|
||||
row = self.cur.fetchone()
|
||||
if row:
|
||||
@@ -30,15 +37,32 @@ class User(object):
|
||||
self.displayname = row['displayname']
|
||||
self.language = row['language']
|
||||
self.role = row['role']
|
||||
self.flags = row['flags']
|
||||
self.flags = row['flags'].split(',') if row['flags'] else []
|
||||
else:
|
||||
self.data = None
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
Speichern eines Benutzers ist momentan nicht vorgesehen
|
||||
"""
|
||||
pass
|
||||
fields = ('login', 'displayname', 'language', 'role')
|
||||
sqlfield = []
|
||||
values = []
|
||||
for field in fields:
|
||||
newdata = getattr(self, field)
|
||||
if self.data[field] != newdata:
|
||||
sqlfield.append(f"{field}=%s")
|
||||
values.append(newdata)
|
||||
self.data[field] = newdata
|
||||
# flags set handled separately
|
||||
newflags = ','.join(self.flags) if self.flags else None
|
||||
if self.data['flags'] != newflags:
|
||||
sqlfield.append(f"flags=%s")
|
||||
values.append(newflags)
|
||||
self.data['flags'] = newflags
|
||||
if values:
|
||||
# only save if changed values exist
|
||||
sql = "UPDATE user SET " + ",".join(sqlfield) + " WHERE userid=%s"
|
||||
values.append(self.user_id)
|
||||
self.cur.execute(sql, values)
|
||||
self.conn.commit()
|
||||
|
||||
""" unused at the moment
|
||||
def mark_login(self):
|
||||
@@ -52,6 +76,51 @@ class User(object):
|
||||
self.conn.commit()
|
||||
"""
|
||||
|
||||
def create(self):
|
||||
"""
|
||||
Creates a new user with the first free id > 0
|
||||
The role is the lowest possible one
|
||||
"""
|
||||
sql = (
|
||||
"SELECT MIN(u1.userid+1) AS newid "
|
||||
"FROM user AS u1 LEFT JOIN user AS u2 ON u2.userid=u1.userid+1 "
|
||||
"WHERE u1.userid>=0 AND u2.userid IS NULL")
|
||||
self.cur.execute(sql)
|
||||
newid = self.cur.fetchone()['newid']
|
||||
self.user_id = newid
|
||||
# TODO check if login is unused else create other name
|
||||
# add function for that feature
|
||||
self.login = f"user{newid}"
|
||||
self.displayname = f"User #{newid}"
|
||||
self.language = 'en'
|
||||
self.role = 'sailor'
|
||||
self.flags = None
|
||||
sql = (
|
||||
"INSERT INTO user (userid, login, pass, displayname, role, flags, language) "
|
||||
"VALUES (%s,%s,%s,%s,%s,%s,%s)"
|
||||
)
|
||||
cryptpass = bcrypt.hashpw(self.genpass().encode(), bcrypt.gensalt())
|
||||
self.cur.execute(sql, (newid, self.login, cryptpass, self.displayname, self.role, self.flags, self.language))
|
||||
# create mandatory settings
|
||||
sql = "INSERT INTO settings (userid, sno, valint) VALUES (%s, 1, 0)"
|
||||
self.cur.execute(sql, (newid,))
|
||||
self.conn.commit()
|
||||
return newid
|
||||
|
||||
def delete(self):
|
||||
sql = "DELETE FROM settings WHERE userid=%s"
|
||||
self.cur.execute(sql, (self.user_id,))
|
||||
sql = "DELETE FROM user WHERE userid=%s"
|
||||
self.cur.execute(sql, (self.user_id,))
|
||||
self.conn.commit()
|
||||
|
||||
def setpass(self, newpass):
|
||||
sql = "UPDATE user SET pass=%s WHERE userid=%s"
|
||||
cryptpass = bcrypt.hashpw(newpass.encode(), bcrypt.gensalt())
|
||||
print(cryptpass, self.user_id)
|
||||
self.cur.execute(sql, (cryptpass, self.user_id))
|
||||
self.conn.commit()
|
||||
|
||||
def __repr__(self):
|
||||
# Unique description
|
||||
out = "User(%d)" % self.user_id
|
||||
|
||||
@@ -30,7 +30,8 @@ gi.require_version('Rsvg', '2.0')
|
||||
from gi.repository import GLib, Gtk, Rsvg
|
||||
|
||||
from yms import database
|
||||
from yms import gtkutils
|
||||
from yms import gtkutils, combobox, treeview
|
||||
from yms import user
|
||||
|
||||
cfg = {
|
||||
'cfgfile': '~/.config/ymsgui.conf',
|
||||
@@ -69,10 +70,11 @@ class Frontend():
|
||||
self.vname = "Ghost(0)"
|
||||
|
||||
# get list of vessels
|
||||
db.cur.execute("SELECT vid, vesselname, model FROM vessel ORDER BY vid")
|
||||
for row in db.cur.fetchall():
|
||||
print(row)
|
||||
print(type(self.combo['vessel']))
|
||||
vessel = {}
|
||||
db.dcur.execute("SELECT vid, vesselname, model FROM vessel ORDER BY vid")
|
||||
for row in db.dcur.fetchall():
|
||||
vessel[row['vid']] = row['vesselname'] + " - " + row['model']
|
||||
combobox.load_from_dict(self.combo['vessel'], vessel, self.vid)
|
||||
|
||||
# load shape of vessel if available
|
||||
handle = Rsvg.Handle()
|
||||
@@ -84,17 +86,97 @@ class Frontend():
|
||||
#viewport.height = 240
|
||||
#self._svg.render_document(ctx, viewport)
|
||||
|
||||
# combos
|
||||
roles = {'captain': 'Captain', 'helmsman': 'Helmsman', 'sailor': 'Sailor'}
|
||||
combobox.load_from_dict(self.combo['user_role'], roles)
|
||||
langs = {'de': 'Deutsch', 'en': 'English'}
|
||||
combobox.load_from_dict(self.combo['user_lang'], langs)
|
||||
|
||||
# prepare lists
|
||||
self.lst_user = Gtk.ListStore(int, str)
|
||||
db.cur.execute("SELECT userid, login FROM user ORDER BY login")
|
||||
db.cur.execute("SELECT userid, login FROM user WHERE userid > 0 ORDER BY login")
|
||||
for row in db.cur.fetchall():
|
||||
self.lst_user.append(row)
|
||||
treeview.add_column(self.tree['user'], 'ID', 0)
|
||||
treeview.add_column(self.tree['user'], 'Login', 1)
|
||||
self.tree['user'].set_model(self.lst_user)
|
||||
|
||||
# current selected objects
|
||||
self._user = user.User(db.conn, 0)
|
||||
print(self._user)
|
||||
|
||||
def run(self):
|
||||
self.label['vessel'].set_text(self.vname)
|
||||
self.window.show_all()
|
||||
Gtk.main()
|
||||
|
||||
def user_display(self)
|
||||
self.entry['user_login'].set_text(self._user.login)
|
||||
self.entry['user_displayname'].set_text(self._user.displayname)
|
||||
combobox.activate_row(self.combo['user_role'], self._user.role)
|
||||
combobox.activate_row(self.combo['user_lang'], self._user.language)
|
||||
self.check['user_locked'].set_active('locked' in self._user.flags)
|
||||
self.check['user_deleted'].set_active('deleted' in self._user.flags)
|
||||
self.entry['user_pass'].set_text('')
|
||||
|
||||
def on_tvw_user_row_activated(self, widget, path, column):
|
||||
# load selected user
|
||||
self._user.user_id = treeview.get_value(widget, 0)
|
||||
self._user.load()
|
||||
self.user_display()
|
||||
|
||||
def on_but_user_new_clicked(self, widget):
|
||||
# get first free user id and create a new record with name "user<nnn>"
|
||||
self._user.create()
|
||||
self.lst_user.append((self._user.user_id, self._user.login))
|
||||
|
||||
def on_but_user_del_clicked(self, widget):
|
||||
print("Delete user")
|
||||
self._user.delete()
|
||||
selection = self.tree['user'].get_selection()
|
||||
model, tree_iter = selection.get_selected()
|
||||
model.remove(tree_iter)
|
||||
# TODO Select some other user from new list selection
|
||||
self._user.user_id = treeview.get_value(self.tree['user'])
|
||||
self._user.load()
|
||||
self.user_display()
|
||||
|
||||
def on_but_user_newpass_clicked(self, widget):
|
||||
self.entry['user_pass'].set_text(user.User.genpass())
|
||||
# self.lst_user.
|
||||
|
||||
def on_but_user_save_clicked(self, widget):
|
||||
newlogin = self.entry['user_login'].get_text()
|
||||
# check if changed login exists and throw error in that case
|
||||
if newlogin != self._user.login:
|
||||
sql = "SELECT COUNT(login) FROM user WHERE login=%s"
|
||||
db.cur.execute(sql, (newlogin, ))
|
||||
if db.cur.fetchone()[0] > 0:
|
||||
# TODO set error indicator
|
||||
print("Error: Login already exists!")
|
||||
return
|
||||
sql = "UPDATE user SET login=%s WHERE userid=%s"
|
||||
db.cur.execute(sql, (newlogin, self._user.user_id))
|
||||
treeview.set_value(self.tree['user'], 1, newlogin)
|
||||
self._user.displayname = self.entry['user_displayname'].get_text()
|
||||
self._user.role = combobox.get_list_value(self.combo['user_role'])
|
||||
self._user.language = combobox.get_list_value(self.combo['user_lang'])
|
||||
self._user.flags = []
|
||||
if self.check['user_locked'].get_active(): self._user.flags.append('locked')
|
||||
if self.check['user_deleted'].get_active(): self._user.flags.append('deleted')
|
||||
self._user.save()
|
||||
# password field is different. if filled set new password
|
||||
newpass = self.entry['user_pass'].get_text()
|
||||
if len(newpass) >= 8:
|
||||
try:
|
||||
self._user.setpass(newpass)
|
||||
finally:
|
||||
newpass = None
|
||||
self.entry['user_pass'].set_text('')
|
||||
else:
|
||||
# Password to short
|
||||
pass
|
||||
|
||||
def on_but_info_clicked(self, widget):
|
||||
# Userlist
|
||||
sql = ("SELECT userid, login, displayname FROM user ORDER BY login")
|
||||
|
||||