signalk-maintenance-tracker 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -0
- package/README.md +49 -14
- package/dist/api/router.js +25 -6
- package/dist/api/router.js.map +1 -1
- package/dist/auth.js +14 -0
- package/dist/auth.js.map +1 -1
- package/dist/config.js +38 -9
- package/dist/config.js.map +1 -1
- package/dist/db/consumables.repo.js +63 -0
- package/dist/db/consumables.repo.js.map +1 -0
- package/dist/db/migrations.js +46 -0
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/tasks.repo.js +12 -5
- package/dist/db/tasks.repo.js.map +1 -1
- package/dist/domain/status.js +63 -19
- package/dist/domain/status.js.map +1 -1
- package/dist/index.js +17 -4
- package/dist/index.js.map +1 -1
- package/dist/service.js +150 -11
- package/dist/service.js.map +1 -1
- package/dist/signalk/notifications.js +32 -22
- package/dist/signalk/notifications.js.map +1 -1
- package/dist/signalk/paths.js +55 -0
- package/dist/signalk/paths.js.map +1 -0
- package/dist/stowage/client.js +200 -0
- package/dist/stowage/client.js.map +1 -0
- package/package.json +7 -4
- package/public/app/api/hooks.js +1 -1
- package/public/app/api/stowage.js +88 -0
- package/public/app/components/ConsumablesPicker.js +141 -0
- package/public/app/components/DownloadLogModal.js +95 -0
- package/public/app/components/LogEntryModal.js +98 -1
- package/public/app/components/PlacementAllocator.js +154 -0
- package/public/app/components/StockBadge.js +52 -0
- package/public/app/components/TagInput.js +3 -0
- package/public/app/components/TaskFormModal.js +120 -1
- package/public/app/lib/format.js +28 -0
- package/public/app/lib/logExport.js +108 -0
- package/public/app/pages/MasterLogPage.js +29 -79
- package/public/app/pages/TaskDetailPage.js +103 -16
- package/public/app/pages/TaskListPage.js +32 -50
- package/public/app/types.js +26 -2
- package/public/styles/main.css +92 -33
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
# v1.1.0
|
|
2
|
+
|
|
3
|
+
This release teaches Maintenance Tracker to talk to your spares locker, adds
|
|
4
|
+
finer control over when tasks come due and warn, and makes the log easy to take
|
|
5
|
+
with you.
|
|
6
|
+
|
|
7
|
+
## Highlights
|
|
8
|
+
|
|
9
|
+
- **Inventory integration with signalk-stowage-mgmt.** Link the parts a task
|
|
10
|
+
consumes straight to your stowage-mgmt items, see live stock badges
|
|
11
|
+
(`In stock` / `Low stock` / `Out of stock`) beside each task's due-date badge,
|
|
12
|
+
and have the used quantities auto-decremented from inventory when you mark a
|
|
13
|
+
task complete — choosing which location(s) the stock came from when a part
|
|
14
|
+
lives in more than one place. Entirely opt-in: leave the stowage-mgmt API URL
|
|
15
|
+
blank and none of it activates.
|
|
16
|
+
- **Per-task warning windows.** Any task can override the plugin-wide "due soon"
|
|
17
|
+
lead windows with its own runtime-hours and calendar-days thresholds, so a
|
|
18
|
+
critical task can warn earlier without changing everything else.
|
|
19
|
+
- **One-time due-date deadlines.** Give a task a specific calendar due date for a
|
|
20
|
+
one-off job, independent of any recurring interval.
|
|
21
|
+
- **Download the log.** Export the maintenance log as CSV, Markdown, or JSON from
|
|
22
|
+
a format-picker in the webapp.
|
|
23
|
+
- **Publish task data to SignalK paths.** Beyond notifications, each task can now
|
|
24
|
+
publish to `maintenance.{slug}.data` and `maintenance.{slug}.status`
|
|
25
|
+
(toggleable), so dashboards can read task details directly from the SignalK
|
|
26
|
+
data model.
|
|
27
|
+
- **Configurable alarm state per status.** Choose the SignalK alarm state
|
|
28
|
+
(`none`/`normal`/`alert`/`warn`/`alarm`/`emergency`) raised for up-to-date,
|
|
29
|
+
due-soon, and overdue tasks independently. The old notification "method" option
|
|
30
|
+
is gone.
|
|
31
|
+
|
|
32
|
+
## Smaller changes and fixes
|
|
33
|
+
|
|
34
|
+
- Task list and detail UI cleanup: action buttons moved into a toolbar, page
|
|
35
|
+
headers dropped, Tags and Next Due columns removed, Status column widened for
|
|
36
|
+
badges, and larger icons and fonts for readability on chartplotters.
|
|
37
|
+
- Tags are now added when you Tab out of the tag input, not only on Enter.
|
|
38
|
+
- Device-token principals are redacted and long SignalK token usernames are
|
|
39
|
+
shortened in the log's "By" column.
|
|
40
|
+
- The pre-commit hook now checks formatting instead of silently auto-fixing.
|
|
41
|
+
|
|
1
42
|
# v1.0.0
|
|
2
43
|
|
|
3
44
|
The first release of Maintenance Tracker! 🎉
|
package/README.md
CHANGED
|
@@ -8,15 +8,24 @@ else that comes due by engine hours, by calendar time, or both.
|
|
|
8
8
|
|
|
9
9
|
- **Tasks with two interval dimensions** — runtime hours (read live from a
|
|
10
10
|
SignalK path such as `propulsion.port.runTime`) and/or calendar time
|
|
11
|
-
(days/weeks/months/years).
|
|
12
|
-
informational
|
|
11
|
+
(days/weeks/months/years). Add a one-time calendar due date for a one-off
|
|
12
|
+
job, or leave every interval blank to keep a plain informational record.
|
|
13
13
|
- **Status tracking** — each task is `overdue`, `due soon`, `ok`, or
|
|
14
|
-
`unknown`; the task list sorts most-urgent first.
|
|
14
|
+
`unknown`; the task list sorts most-urgent first. Any task can override the
|
|
15
|
+
plugin-wide "due soon" lead windows with its own runtime-hours and
|
|
16
|
+
calendar-days thresholds.
|
|
15
17
|
- **Maintenance log** — per-task history plus a master log across all tasks,
|
|
16
|
-
with markdown notes and who logged the work.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
with markdown notes and who logged the work. Export the log as CSV,
|
|
19
|
+
Markdown, or JSON.
|
|
20
|
+
- **Inventory integration** — link the parts a task consumes to your
|
|
21
|
+
[signalk-stowage-mgmt](https://www.npmjs.com/package/signalk-stowage-mgmt)
|
|
22
|
+
inventory, see live stock badges next to each task, and auto-decrement stock
|
|
23
|
+
when a task is completed. Fully opt-in (see below).
|
|
24
|
+
- **SignalK notifications and paths** — overdue/due-soon status is published to
|
|
25
|
+
`notifications.maintenance.{slug}` with a configurable alarm state per task
|
|
26
|
+
status, and each task can also publish to `maintenance.{slug}.data` and
|
|
27
|
+
`maintenance.{slug}.status`, so it shows up in any SignalK notification
|
|
28
|
+
consumer or dashboard.
|
|
20
29
|
- **Modern webapp** — buildless Preact SPA served from the SignalK webapps
|
|
21
30
|
menu: searchable/filterable task table, tag chips, progress bars, light/dark
|
|
22
31
|
theme, live polling. Runs on browsers as old as Chromium 69 (Navico/B&G
|
|
@@ -44,13 +53,39 @@ Tracker**; data is stored in the plugin's data directory as `maintenance.db`.
|
|
|
44
53
|
|
|
45
54
|
### Plugin options
|
|
46
55
|
|
|
47
|
-
| option | default
|
|
48
|
-
| ------------------------ |
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
53
|
-
| `
|
|
56
|
+
| option | default | purpose |
|
|
57
|
+
| ------------------------ | ------- | ------------------------------------------------- |
|
|
58
|
+
| `enablePublishPaths` | `true` | publish each task to `maintenance.{slug}.*` paths |
|
|
59
|
+
| `enableNotifications` | `true` | master switch for notification publishing |
|
|
60
|
+
| `alarmStateOk` | `none` | alarm state for up-to-date tasks |
|
|
61
|
+
| `alarmStateDueSoon` | `warn` | alarm state for due-soon tasks |
|
|
62
|
+
| `alarmStateOverdue` | `alarm` | alarm state for overdue tasks |
|
|
63
|
+
| `runtimeNotifyLeadHours` | `10` | runtime hours before due to raise "due soon" |
|
|
64
|
+
| `timeNotifyLeadDays` | `7` | days before due to raise "due soon" |
|
|
65
|
+
| `recomputeIntervalMs` | `60000` | status recompute tick in ms |
|
|
66
|
+
| `stowageMgmtUrl` | `''` | signalk-stowage-mgmt API URL (blank = disabled) |
|
|
67
|
+
|
|
68
|
+
## 🔧 Inventory integration: signalk-stowage-mgmt
|
|
69
|
+
|
|
70
|
+
Maintenance tasks can now link directly to your
|
|
71
|
+
[signalk-stowage-mgmt](https://www.npmjs.com/package/signalk-stowage-mgmt)
|
|
72
|
+
inventory. Set the **signalk-stowage-mgmt API URL** option (e.g.
|
|
73
|
+
`http://localhost:3000/plugins/signalk-stowage-mgmt`) to turn it on:
|
|
74
|
+
|
|
75
|
+
- **Link parts to tasks** — "Oil change" needs a filter and 5 L of oil? Tag
|
|
76
|
+
them right in the task editor, autocompleted straight from your stowage-mgmt
|
|
77
|
+
items.
|
|
78
|
+
- **See stock at a glance** — tasks show `In stock` / `Low stock` /
|
|
79
|
+
`Out of stock` right next to the due-date badge. No more "task's due but I'm
|
|
80
|
+
out of filters" surprises.
|
|
81
|
+
- **Auto-decrement on completion** — mark a task done and it knocks the used
|
|
82
|
+
quantity off your inventory automatically (opt-in checkbox, on by default).
|
|
83
|
+
- **Split across locations? You pick.** If a part lives in more than one spot on
|
|
84
|
+
the boat, you choose which location(s) it came from right in the completion
|
|
85
|
+
dialog — no guessing on the software's part.
|
|
86
|
+
|
|
87
|
+
**Fully optional** — leave the API URL blank (the default) and none of this does
|
|
88
|
+
anything.
|
|
54
89
|
|
|
55
90
|
## REST API
|
|
56
91
|
|
package/dist/api/router.js
CHANGED
|
@@ -3,6 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.mountApi = mountApi;
|
|
4
4
|
const auth_1 = require("../auth");
|
|
5
5
|
const service_1 = require("../service");
|
|
6
|
+
/** Cookie/authorization headers from the incoming request, forwarded
|
|
7
|
+
* verbatim when we call out to signalk-stowage-mgmt on the caller's behalf
|
|
8
|
+
* (docs/inventory-interaction.md — no separate service credentials). */
|
|
9
|
+
function forwardableHeaders(req) {
|
|
10
|
+
const headers = {};
|
|
11
|
+
const cookie = req.headers.cookie;
|
|
12
|
+
const auth = req.headers.authorization;
|
|
13
|
+
if (typeof cookie === 'string')
|
|
14
|
+
headers.cookie = cookie;
|
|
15
|
+
if (typeof auth === 'string')
|
|
16
|
+
headers.authorization = auth;
|
|
17
|
+
return headers;
|
|
18
|
+
}
|
|
6
19
|
/**
|
|
7
20
|
* Mounts the plugin REST API (§8) on the router SignalK provides via
|
|
8
21
|
* registerWithRouter. The router is mounted at /plugins/{pluginId}, so routes
|
|
@@ -21,10 +34,7 @@ function mountApi(router, getServices) {
|
|
|
21
34
|
});
|
|
22
35
|
return;
|
|
23
36
|
}
|
|
24
|
-
|
|
25
|
-
fn(services, req, res);
|
|
26
|
-
}
|
|
27
|
-
catch (err) {
|
|
37
|
+
const handleError = (err) => {
|
|
28
38
|
if (err instanceof service_1.ApiError) {
|
|
29
39
|
res
|
|
30
40
|
.status(err.status)
|
|
@@ -38,6 +48,15 @@ function mountApi(router, getServices) {
|
|
|
38
48
|
},
|
|
39
49
|
});
|
|
40
50
|
}
|
|
51
|
+
};
|
|
52
|
+
try {
|
|
53
|
+
const result = fn(services, req, res);
|
|
54
|
+
if (result && typeof result.then === 'function') {
|
|
55
|
+
result.catch(handleError);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
handleError(err);
|
|
41
60
|
}
|
|
42
61
|
};
|
|
43
62
|
// ---- tasks (§8.1) ----
|
|
@@ -61,9 +80,9 @@ function mountApi(router, getServices) {
|
|
|
61
80
|
router.get('/api/tasks/:slug/logs', withServices((s, req, res) => {
|
|
62
81
|
res.json({ data: s.service.listTaskLogs(req.params.slug) });
|
|
63
82
|
}));
|
|
64
|
-
router.post('/api/tasks/:slug/logs', withServices((s, req, res) => {
|
|
83
|
+
router.post('/api/tasks/:slug/logs', withServices(async (s, req, res) => {
|
|
65
84
|
// logged_by comes from the SignalK principal, never the body (§9.1)
|
|
66
|
-
const entry = s.service.addLog(req.params.slug, req.body ?? {}, (0, auth_1.getRequestUser)(req));
|
|
85
|
+
const entry = await s.service.addLog(req.params.slug, req.body ?? {}, (0, auth_1.getRequestUser)(req), forwardableHeaders(req));
|
|
67
86
|
res.status(201).json(entry);
|
|
68
87
|
}));
|
|
69
88
|
router.get('/api/logs', withServices((s, req, res) => {
|
package/dist/api/router.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getRequestUser = getRequestUser;
|
|
4
|
+
exports.publicUser = publicUser;
|
|
4
5
|
/**
|
|
5
6
|
* Read the SignalK request principal's identifier, used only to stamp
|
|
6
7
|
* log_entries.logged_by (§9.1). The plugin does no authorization of its own —
|
|
@@ -19,4 +20,17 @@ function getRequestUser(req) {
|
|
|
19
20
|
(typeof r?.user === 'string' ? r.user : null) ??
|
|
20
21
|
null);
|
|
21
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Device-token principals identify as a raw UUID (e.g.
|
|
25
|
+
* "158dccd5-f82c-42a3-9909-42ac7d3c8e88") rather than a human username. The
|
|
26
|
+
* read-only API may be public, so the full identifier must never leave the
|
|
27
|
+
* server: shorten tokens to their first segment before serializing. Human
|
|
28
|
+
* usernames pass through unchanged.
|
|
29
|
+
*/
|
|
30
|
+
const TOKEN_USER_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
31
|
+
function publicUser(loggedBy) {
|
|
32
|
+
if (!loggedBy)
|
|
33
|
+
return loggedBy;
|
|
34
|
+
return TOKEN_USER_RE.test(loggedBy) ? loggedBy.slice(0, 8) : loggedBy;
|
|
35
|
+
}
|
|
22
36
|
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":";;AAQA,wCAWC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":";;AAQA,wCAWC;AAYD,gCAGC;AAlCD;;;;;;;GAOG;AACH,SAAgB,cAAc,CAAC,GAAY;IACzC,MAAM,CAAC,GAAG,GAA0B,CAAC;IACrC,OAAO,CACL,CAAC,EAAE,WAAW,EAAE,UAAU;QAC1B,CAAC,EAAE,MAAM,EAAE,EAAE;QACb,CAAC,EAAE,MAAM,EAAE,QAAQ;QACnB,CAAC,EAAE,IAAI,EAAE,EAAE;QACX,CAAC,EAAE,IAAI,EAAE,QAAQ;QACjB,CAAC,OAAO,CAAC,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7C,IAAI,CACL,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,aAAa,GACjB,iEAAiE,CAAC;AAEpE,SAAgB,UAAU,CAAC,QAAuB;IAChD,IAAI,CAAC,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC/B,OAAO,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;AACxE,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -2,41 +2,64 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.schema = exports.DEFAULT_OPTIONS = void 0;
|
|
4
4
|
exports.withDefaults = withDefaults;
|
|
5
|
+
const ALARM_STATES = [
|
|
6
|
+
'none',
|
|
7
|
+
'normal',
|
|
8
|
+
'alert',
|
|
9
|
+
'warn',
|
|
10
|
+
'alarm',
|
|
11
|
+
'emergency',
|
|
12
|
+
];
|
|
5
13
|
exports.DEFAULT_OPTIONS = {
|
|
14
|
+
enablePublishPaths: true,
|
|
6
15
|
enableNotifications: true,
|
|
7
|
-
|
|
16
|
+
alarmStateOk: 'none',
|
|
17
|
+
alarmStateDueSoon: 'warn',
|
|
18
|
+
alarmStateOverdue: 'alarm',
|
|
8
19
|
runtimeNotifyLeadHours: 10,
|
|
9
20
|
timeNotifyLeadDays: 7,
|
|
10
21
|
recomputeIntervalMs: 60000,
|
|
22
|
+
stowageMgmtUrl: '',
|
|
11
23
|
};
|
|
12
24
|
function withDefaults(options) {
|
|
13
25
|
return { ...exports.DEFAULT_OPTIONS, ...(options ?? {}) };
|
|
14
26
|
}
|
|
27
|
+
const alarmStateProperty = (title, defaultValue) => ({
|
|
28
|
+
type: 'string',
|
|
29
|
+
title,
|
|
30
|
+
enum: [...ALARM_STATES],
|
|
31
|
+
default: defaultValue,
|
|
32
|
+
});
|
|
15
33
|
exports.schema = {
|
|
16
34
|
type: 'object',
|
|
17
35
|
properties: {
|
|
36
|
+
enablePublishPaths: {
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
title: 'Publish task data to SignalK paths',
|
|
39
|
+
description: 'Publish each task to maintenance.{slug}.data and its status to maintenance.{slug}.status',
|
|
40
|
+
default: exports.DEFAULT_OPTIONS.enablePublishPaths,
|
|
41
|
+
},
|
|
18
42
|
enableNotifications: {
|
|
19
43
|
type: 'boolean',
|
|
20
44
|
title: 'Enable notifications',
|
|
21
45
|
description: 'Publish overdue/upcoming status to notifications.maintenance.*',
|
|
22
46
|
default: exports.DEFAULT_OPTIONS.enableNotifications,
|
|
23
47
|
},
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
items: { type: 'string', enum: ['visual', 'sound'] },
|
|
28
|
-
default: exports.DEFAULT_OPTIONS.notificationMethods,
|
|
29
|
-
},
|
|
48
|
+
alarmStateOk: alarmStateProperty('Alarm state for up-to-date tasks', exports.DEFAULT_OPTIONS.alarmStateOk),
|
|
49
|
+
alarmStateDueSoon: alarmStateProperty('Alarm state for due-soon tasks', exports.DEFAULT_OPTIONS.alarmStateDueSoon),
|
|
50
|
+
alarmStateOverdue: alarmStateProperty('Alarm state for overdue tasks', exports.DEFAULT_OPTIONS.alarmStateOverdue),
|
|
30
51
|
runtimeNotifyLeadHours: {
|
|
31
52
|
type: 'number',
|
|
32
53
|
title: 'Runtime lead window (hours)',
|
|
33
|
-
|
|
54
|
+
minimum: 0,
|
|
55
|
+
description: 'Tasks within this many runtime hours of due are "due soon". 0 disables the warning — tasks go straight from OK to overdue. Individual tasks can override this.',
|
|
34
56
|
default: exports.DEFAULT_OPTIONS.runtimeNotifyLeadHours,
|
|
35
57
|
},
|
|
36
58
|
timeNotifyLeadDays: {
|
|
37
59
|
type: 'number',
|
|
38
60
|
title: 'Time lead window (days)',
|
|
39
|
-
|
|
61
|
+
minimum: 0,
|
|
62
|
+
description: 'Tasks within this many days of due are "due soon". 0 disables the warning — tasks go straight from OK to overdue. Individual tasks can override this.',
|
|
40
63
|
default: exports.DEFAULT_OPTIONS.timeNotifyLeadDays,
|
|
41
64
|
},
|
|
42
65
|
recomputeIntervalMs: {
|
|
@@ -45,6 +68,12 @@ exports.schema = {
|
|
|
45
68
|
description: 'How often to re-evaluate task status and refresh notifications',
|
|
46
69
|
default: exports.DEFAULT_OPTIONS.recomputeIntervalMs,
|
|
47
70
|
},
|
|
71
|
+
stowageMgmtUrl: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
title: 'signalk-stowage-mgmt API URL',
|
|
74
|
+
description: "Base URL for signalk-stowage-mgmt's API (e.g. http://localhost:3000/plugins/signalk-stowage-mgmt). Leave blank to disable linking tasks to inventory items.",
|
|
75
|
+
default: exports.DEFAULT_OPTIONS.stowageMgmtUrl,
|
|
76
|
+
},
|
|
48
77
|
},
|
|
49
78
|
};
|
|
50
79
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AAyCA,oCAEC;AAvCD,MAAM,YAAY,GAAiB;IACjC,MAAM;IACN,QAAQ;IACR,OAAO;IACP,MAAM;IACN,OAAO;IACP,WAAW;CACZ,CAAC;AAkBW,QAAA,eAAe,GAAkB;IAC5C,kBAAkB,EAAE,IAAI;IACxB,mBAAmB,EAAE,IAAI;IACzB,YAAY,EAAE,MAAM;IACpB,iBAAiB,EAAE,MAAM;IACzB,iBAAiB,EAAE,OAAO;IAC1B,sBAAsB,EAAE,EAAE;IAC1B,kBAAkB,EAAE,CAAC;IACrB,mBAAmB,EAAE,KAAK;IAC1B,cAAc,EAAE,EAAE;CACnB,CAAC;AAEF,SAAgB,YAAY,CAAC,OAAgC;IAC3D,OAAO,EAAE,GAAG,uBAAe,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,kBAAkB,GAAG,CAAC,KAAa,EAAE,YAAwB,EAAE,EAAE,CAAC,CAAC;IACvE,IAAI,EAAE,QAAQ;IACd,KAAK;IACL,IAAI,EAAE,CAAC,GAAG,YAAY,CAAC;IACvB,OAAO,EAAE,YAAY;CACtB,CAAC,CAAC;AAEU,QAAA,MAAM,GAAG;IACpB,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE;QACV,kBAAkB,EAAE;YAClB,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,oCAAoC;YAC3C,WAAW,EACT,0FAA0F;YAC5F,OAAO,EAAE,uBAAe,CAAC,kBAAkB;SAC5C;QACD,mBAAmB,EAAE;YACnB,IAAI,EAAE,SAAS;YACf,KAAK,EAAE,sBAAsB;YAC7B,WAAW,EACT,gEAAgE;YAClE,OAAO,EAAE,uBAAe,CAAC,mBAAmB;SAC7C;QACD,YAAY,EAAE,kBAAkB,CAC9B,kCAAkC,EAClC,uBAAe,CAAC,YAAY,CAC7B;QACD,iBAAiB,EAAE,kBAAkB,CACnC,gCAAgC,EAChC,uBAAe,CAAC,iBAAiB,CAClC;QACD,iBAAiB,EAAE,kBAAkB,CACnC,+BAA+B,EAC/B,uBAAe,CAAC,iBAAiB,CAClC;QACD,sBAAsB,EAAE;YACtB,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,6BAA6B;YACpC,OAAO,EAAE,CAAC;YACV,WAAW,EACT,gKAAgK;YAClK,OAAO,EAAE,uBAAe,CAAC,sBAAsB;SAChD;QACD,kBAAkB,EAAE;YAClB,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,yBAAyB;YAChC,OAAO,EAAE,CAAC;YACV,WAAW,EACT,uJAAuJ;YACzJ,OAAO,EAAE,uBAAe,CAAC,kBAAkB;SAC5C;QACD,mBAAmB,EAAE;YACnB,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,yBAAyB;YAChC,WAAW,EACT,gEAAgE;YAClE,OAAO,EAAE,uBAAe,CAAC,mBAAmB;SAC7C;QACD,cAAc,EAAE;YACd,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,8BAA8B;YACrC,WAAW,EACT,6JAA6J;YAC/J,OAAO,EAAE,uBAAe,CAAC,cAAc;SACxC;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConsumablesRepo = void 0;
|
|
4
|
+
const CONSUMABLE_COLUMNS = `id, task_id, item_id, item_name, qty_per_service, created_at`;
|
|
5
|
+
class ConsumablesRepo {
|
|
6
|
+
db;
|
|
7
|
+
constructor(db) {
|
|
8
|
+
this.db = db;
|
|
9
|
+
}
|
|
10
|
+
forTask(taskId) {
|
|
11
|
+
return this.db
|
|
12
|
+
.prepare(`SELECT ${CONSUMABLE_COLUMNS} FROM task_consumables
|
|
13
|
+
WHERE task_id = ? ORDER BY item_name COLLATE NOCASE`)
|
|
14
|
+
.all(taskId);
|
|
15
|
+
}
|
|
16
|
+
/** One query for the whole task list: task_id -> consumables. */
|
|
17
|
+
byTask() {
|
|
18
|
+
const rows = this.db
|
|
19
|
+
.prepare(`SELECT ${CONSUMABLE_COLUMNS} FROM task_consumables
|
|
20
|
+
ORDER BY item_name COLLATE NOCASE`)
|
|
21
|
+
.all();
|
|
22
|
+
const map = new Map();
|
|
23
|
+
for (const r of rows) {
|
|
24
|
+
const list = map.get(r.task_id) ?? [];
|
|
25
|
+
list.push(r);
|
|
26
|
+
map.set(r.task_id, list);
|
|
27
|
+
}
|
|
28
|
+
return map;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Replace a task's linked consumables wholesale (mirrors
|
|
32
|
+
* TagsRepo.setTaskTags). item_name is re-cached from the input on every
|
|
33
|
+
* call, so re-saving a task after an item was renamed in stowage-mgmt
|
|
34
|
+
* refreshes the cached label.
|
|
35
|
+
*/
|
|
36
|
+
setForTask(taskId, items, nowIso) {
|
|
37
|
+
this.db
|
|
38
|
+
.prepare(`DELETE FROM task_consumables WHERE task_id = ?`)
|
|
39
|
+
.run(taskId);
|
|
40
|
+
const insert = this.db.prepare(`INSERT INTO task_consumables (task_id, item_id, item_name, qty_per_service, created_at)
|
|
41
|
+
VALUES (?, ?, ?, ?, ?)`);
|
|
42
|
+
const seen = new Set();
|
|
43
|
+
for (const item of items) {
|
|
44
|
+
if (seen.has(item.item_id))
|
|
45
|
+
continue; // UNIQUE(task_id, item_id) guard
|
|
46
|
+
seen.add(item.item_id);
|
|
47
|
+
insert.run(taskId, item.item_id, item.item_name, item.qty_per_service, nowIso);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Used to refresh a cached item_name without touching qty_per_service. */
|
|
51
|
+
updateCachedName(itemId, itemName) {
|
|
52
|
+
this.db
|
|
53
|
+
.prepare(`UPDATE task_consumables SET item_name = ? WHERE item_id = ?`)
|
|
54
|
+
.run(itemName, itemId);
|
|
55
|
+
}
|
|
56
|
+
removeForTask(taskId) {
|
|
57
|
+
this.db
|
|
58
|
+
.prepare(`DELETE FROM task_consumables WHERE task_id = ?`)
|
|
59
|
+
.run(taskId);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
exports.ConsumablesRepo = ConsumablesRepo;
|
|
63
|
+
//# sourceMappingURL=consumables.repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consumables.repo.js","sourceRoot":"","sources":["../../src/db/consumables.repo.ts"],"names":[],"mappings":";;;AAkBA,MAAM,kBAAkB,GAAG,8DAA8D,CAAC;AAE1F,MAAa,eAAe;IACN;IAApB,YAAoB,EAAgB;QAAhB,OAAE,GAAF,EAAE,CAAc;IAAG,CAAC;IAExC,OAAO,CAAC,MAAc;QACpB,OAAO,IAAI,CAAC,EAAE;aACX,OAAO,CACN,UAAU,kBAAkB;6DACyB,CACtD;aACA,GAAG,CAAC,MAAM,CAA+B,CAAC;IAC/C,CAAC;IAED,iEAAiE;IACjE,MAAM;QACJ,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CACN,UAAU,kBAAkB;2CACO,CACpC;aACA,GAAG,EAAgC,CAAC;QACvC,MAAM,GAAG,GAAG,IAAI,GAAG,EAA2B,CAAC;QAC/C,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACb,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;;;OAKG;IACH,UAAU,CAAC,MAAc,EAAE,KAAwB,EAAE,MAAc;QACjE,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,gDAAgD,CAAC;aACzD,GAAG,CAAC,MAAM,CAAC,CAAC;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAC5B;8BACwB,CACzB,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;gBAAE,SAAS,CAAC,iCAAiC;YACvE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACvB,MAAM,CAAC,GAAG,CACR,MAAM,EACN,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,eAAe,EACpB,MAAM,CACP,CAAC;QACJ,CAAC;IACH,CAAC;IAED,2EAA2E;IAC3E,gBAAgB,CAAC,MAAc,EAAE,QAAgB;QAC/C,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,6DAA6D,CAAC;aACtE,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC3B,CAAC;IAED,aAAa,CAAC,MAAc;QAC1B,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,gDAAgD,CAAC;aACzD,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC;CACF;AArED,0CAqEC"}
|
package/dist/db/migrations.js
CHANGED
|
@@ -53,5 +53,51 @@ exports.migrations = [
|
|
|
53
53
|
`);
|
|
54
54
|
},
|
|
55
55
|
},
|
|
56
|
+
{
|
|
57
|
+
version: 2,
|
|
58
|
+
up(db) {
|
|
59
|
+
db.exec(`
|
|
60
|
+
-- Links a task to stowage-mgmt items it consumes on completion.
|
|
61
|
+
-- item_id is a *soft* foreign key into another plugin's database
|
|
62
|
+
-- (signalk-stowage-mgmt) — there is no cross-database FK constraint,
|
|
63
|
+
-- so item_name is cached at link time to keep the UI meaningful even
|
|
64
|
+
-- if stowage-mgmt is unreachable or the item has since been deleted
|
|
65
|
+
-- there (docs/inventory-interaction.md). item_id is TEXT to match
|
|
66
|
+
-- stowage-mgmt's own item ids (it primary-keys items as TEXT, not
|
|
67
|
+
-- an autoincrement integer).
|
|
68
|
+
CREATE TABLE task_consumables (
|
|
69
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
70
|
+
task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE,
|
|
71
|
+
item_id TEXT NOT NULL,
|
|
72
|
+
item_name TEXT NOT NULL,
|
|
73
|
+
qty_per_service REAL NOT NULL DEFAULT 1,
|
|
74
|
+
created_at TEXT NOT NULL,
|
|
75
|
+
UNIQUE (task_id, item_id)
|
|
76
|
+
);
|
|
77
|
+
CREATE INDEX idx_task_consumables_task ON task_consumables (task_id);
|
|
78
|
+
`);
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
version: 3,
|
|
83
|
+
up(db) {
|
|
84
|
+
// One-time calendar deadline (registrations, renewals, inspections),
|
|
85
|
+
// independent of the recurring time_interval. Stored as UTC-midnight ISO
|
|
86
|
+
// like maintenance dates; NULL = no deadline.
|
|
87
|
+
db.exec(`ALTER TABLE tasks ADD COLUMN due_date TEXT;`);
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
version: 4,
|
|
92
|
+
up(db) {
|
|
93
|
+
// Per-task "due soon" lead windows overriding the plugin-wide defaults
|
|
94
|
+
// (runtimeNotifyLeadHours / timeNotifyLeadDays). NULL = fall back to the
|
|
95
|
+
// plugin default; 0 = no warning window (task jumps ok → overdue).
|
|
96
|
+
// time_warning_days covers both time sub-dimensions (recurring schedule
|
|
97
|
+
// and one-time due date), which share the same date-based status logic.
|
|
98
|
+
db.exec(`ALTER TABLE tasks ADD COLUMN runtime_warning_hours REAL;`);
|
|
99
|
+
db.exec(`ALTER TABLE tasks ADD COLUMN time_warning_days REAL;`);
|
|
100
|
+
},
|
|
101
|
+
},
|
|
56
102
|
];
|
|
57
103
|
//# sourceMappingURL=migrations.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/db/migrations.ts"],"names":[],"mappings":";;;AAOa,QAAA,UAAU,GAAgB;IACrC;QACE,OAAO,EAAE,CAAC;QACV,EAAE,CAAC,EAAE;YACH,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6CP,CAAC,CAAC;QACL,CAAC;KACF;CACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../../src/db/migrations.ts"],"names":[],"mappings":";;;AAOa,QAAA,UAAU,GAAgB;IACrC;QACE,OAAO,EAAE,CAAC;QACV,EAAE,CAAC,EAAE;YACH,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6CP,CAAC,CAAC;QACL,CAAC;KACF;IACD;QACE,OAAO,EAAE,CAAC;QACV,EAAE,CAAC,EAAE;YACH,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;OAmBP,CAAC,CAAC;QACL,CAAC;KACF;IACD;QACE,OAAO,EAAE,CAAC;QACV,EAAE,CAAC,EAAE;YACH,qEAAqE;YACrE,yEAAyE;YACzE,8CAA8C;YAC9C,EAAE,CAAC,IAAI,CAAC,6CAA6C,CAAC,CAAC;QACzD,CAAC;KACF;IACD;QACE,OAAO,EAAE,CAAC;QACV,EAAE,CAAC,EAAE;YACH,uEAAuE;YACvE,yEAAyE;YACzE,mEAAmE;YACnE,wEAAwE;YACxE,wEAAwE;YACxE,EAAE,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;YACpE,EAAE,CAAC,IAAI,CAAC,sDAAsD,CAAC,CAAC;QAClE,CAAC;KACF;CACF,CAAC"}
|
package/dist/db/tasks.repo.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TasksRepo = void 0;
|
|
4
4
|
const COLUMNS = `id, slug, name, description, runtime_interval, time_interval,
|
|
5
|
-
time_interval_unit, runtime_path,
|
|
5
|
+
time_interval_unit, runtime_path, due_date, runtime_warning_hours,
|
|
6
|
+
time_warning_days, last_maintenance, last_runtime,
|
|
6
7
|
seed_last_maintenance, seed_last_runtime, created_at, updated_at`;
|
|
7
8
|
class TasksRepo {
|
|
8
9
|
db;
|
|
@@ -12,10 +13,11 @@ class TasksRepo {
|
|
|
12
13
|
create(t, nowIso) {
|
|
13
14
|
const result = this.db
|
|
14
15
|
.prepare(`INSERT INTO tasks (slug, name, description, runtime_interval, time_interval,
|
|
15
|
-
time_interval_unit, runtime_path,
|
|
16
|
+
time_interval_unit, runtime_path, due_date, runtime_warning_hours,
|
|
17
|
+
time_warning_days, last_maintenance, last_runtime,
|
|
16
18
|
seed_last_maintenance, seed_last_runtime, created_at, updated_at)
|
|
17
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
18
|
-
.run(t.slug, t.name, t.description, t.runtime_interval, t.time_interval, t.time_interval_unit, t.runtime_path, t.last_maintenance, t.last_runtime, t.seed_last_maintenance, t.seed_last_runtime, nowIso, nowIso);
|
|
19
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
20
|
+
.run(t.slug, t.name, t.description, t.runtime_interval, t.time_interval, t.time_interval_unit, t.runtime_path, t.due_date, t.runtime_warning_hours, t.time_warning_days, t.last_maintenance, t.last_runtime, t.seed_last_maintenance, t.seed_last_runtime, nowIso, nowIso);
|
|
19
21
|
return this.getById(Number(result.lastInsertRowid));
|
|
20
22
|
}
|
|
21
23
|
getById(id) {
|
|
@@ -49,16 +51,21 @@ class TasksRepo {
|
|
|
49
51
|
this.db
|
|
50
52
|
.prepare(`UPDATE tasks SET slug = ?, name = ?, description = ?, runtime_interval = ?,
|
|
51
53
|
time_interval = ?, time_interval_unit = ?, runtime_path = ?,
|
|
54
|
+
due_date = ?, runtime_warning_hours = ?, time_warning_days = ?,
|
|
52
55
|
last_maintenance = ?, last_runtime = ?,
|
|
53
56
|
seed_last_maintenance = ?, seed_last_runtime = ?, updated_at = ?
|
|
54
57
|
WHERE id = ?`)
|
|
55
|
-
.run(t.slug, t.name, t.description, t.runtime_interval, t.time_interval, t.time_interval_unit, t.runtime_path, t.last_maintenance, t.last_runtime, t.seed_last_maintenance, t.seed_last_runtime, nowIso, id);
|
|
58
|
+
.run(t.slug, t.name, t.description, t.runtime_interval, t.time_interval, t.time_interval_unit, t.runtime_path, t.due_date, t.runtime_warning_hours, t.time_warning_days, t.last_maintenance, t.last_runtime, t.seed_last_maintenance, t.seed_last_runtime, nowIso, id);
|
|
56
59
|
}
|
|
57
60
|
setLast(id, lastMaintenance, lastRuntime) {
|
|
58
61
|
this.db
|
|
59
62
|
.prepare(`UPDATE tasks SET last_maintenance = ?, last_runtime = ? WHERE id = ?`)
|
|
60
63
|
.run(lastMaintenance, lastRuntime, id);
|
|
61
64
|
}
|
|
65
|
+
/** Clear a task's one-time due date (a completed deadline no longer applies). */
|
|
66
|
+
clearDueDate(id) {
|
|
67
|
+
this.db.prepare(`UPDATE tasks SET due_date = NULL WHERE id = ?`).run(id);
|
|
68
|
+
}
|
|
62
69
|
delete(id) {
|
|
63
70
|
this.db.prepare(`DELETE FROM tasks WHERE id = ?`).run(id);
|
|
64
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tasks.repo.js","sourceRoot":"","sources":["../../src/db/tasks.repo.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"tasks.repo.js","sourceRoot":"","sources":["../../src/db/tasks.repo.ts"],"names":[],"mappings":"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"}
|