Skip to content

Commit

Permalink
Notifications: all messages in chrono order; added timestamps and gro…
Browse files Browse the repository at this point in the history
…uping (evcc-io#1102)
  • Loading branch information
naltatis authored May 30, 2021
1 parent e34877f commit eede2e8
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 24 deletions.
2 changes: 1 addition & 1 deletion .storybook/preview-head.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<link href="/css/bootstrap.min.css" rel="stylesheet" />
<script src="/js/bootstrap.min.js"></script>
<script src="/js/bootstrap.min.js" async></script>

<link href="/css/app.css" rel="stylesheet" />
17 changes: 15 additions & 2 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,21 @@ window.app = new Vue({
methods: {
raise: function (msg) {
console[msg.type](msg);
const withoutThisMsg = this.notifications.filter((m) => m.message !== msg.message);
this.notifications = [msg, ...withoutThisMsg];
const now = new Date();
const latestMsg = this.notifications[0];
if (latestMsg && latestMsg.message === msg.message) {
latestMsg.count++;
latestMsg.time = now;
} else {
this.notifications = [
{
...msg,
count: 1,
time: now,
},
...this.notifications,
];
}
},
clear: function () {
this.notifications = [];
Expand Down
32 changes: 32 additions & 0 deletions assets/js/components/Notifications.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,53 @@ const Template = (args, { argTypes }) => ({
template: '<Notifications v-bind="$props"></Notifications>',
});

function timeAgo(hours = 0, minutes = 0, seconds = 0) {
const date = new Date();
date.setHours(date.getHours() - hours);
date.setMinutes(date.getMinutes() - minutes);
date.setSeconds(date.getSeconds() - seconds);
return date;
}

export const Base = Template.bind({});
Base.args = {
notifications: [
{
message: "Server unavailable",
type: "error",
time: timeAgo(),
count: 1,
},
{
message: "charger out of sync: expected disabled, got enabled",
type: "warn",
count: 4,
time: timeAgo(0, 0, 42),
},
{
message: "Sponsortoken: x509: certificate has expired",
type: "error",
count: 1,
time: timeAgo(1, 12, 44),
},
{
message: "charger out of sync: expected disabled, got enabled",
type: "warn",
count: 4,
time: timeAgo(1, 22, 0),
},
{
message: "vehicle remote charge start: invalid character '<' looking for beginning of value",
type: "warn",
count: 3,
time: timeAgo(4, 2, 0),
},
{
message:
"Amet irure quis incididunt voluptate esse. Commodo ea sunt est ipsum tempor nisi laboris voluptate labore elit laborum. Ex irure commodo reprehenderit consequat consequat do ad tempor aliquip deserunt eu. Laboris minim nostrud quis nisi. Dolor occaecat reprehenderit velit dolore exercitation cupidatat et voluptate. Nulla pariatur deserunt esse minim nisi nisi nulla. Sit eiusmod do incididunt sint minim pariatur aute.",
type: "warn",
count: 1,
time: timeAgo(5, 2, 44),
},
],
};
49 changes: 33 additions & 16 deletions assets/js/components/Notifications.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,30 @@
></button>
</div>
<div class="modal-body">
<p
v-for="(notification, index) in notifications"
:key="index"
class="d-flex align-items-baseline"
>
<fa-icon
:class="{
'text-danger': notification.type === 'error',
'text-warning': notification.type === 'warn',
}"
class="flex-grow-0 d-block"
icon="exclamation-triangle"
></fa-icon>
<span class="flex-grow-1 px-2 py-1">{{ notification.message }}</span>
</p>
<div v-for="(msg, index) in notifications" :key="index">
<small
class="d-flex justify-content-end mt-3"
:title="fmtAbsoluteDate(msg.time)"
>
{{ fmtTimeAgo(msg.time) }}
</small>
<p class="d-flex align-items-baseline">
<fa-icon
:class="{
'text-danger': msg.type === 'error',
'text-warning': msg.type === 'warn',
}"
class="flex-grow-0 d-block"
icon="exclamation-triangle"
></fa-icon>
<span class="flex-grow-1 px-2 py-1">
{{ msg.message }}
</span>
<span class="badge rounded-pill bg-secondary" v-if="msg.count > 1">
{{ msg.count }}
</span>
</p>
</div>
</div>
<div class="modal-footer">
<button
Expand Down Expand Up @@ -83,9 +92,17 @@ export default {
},
methods: {
clear: function () {
window.app.clear();
window.app && window.app.clear();
},
},
created: function () {
this.interval = setInterval(() => {
this.$forceUpdate();
}, 10 * 1000);
},
destroyed: function () {
clearTimeout(this.interval);
},
mixins: [formatter],
};
</script>
18 changes: 18 additions & 0 deletions assets/js/mixins/formatter.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,23 @@ export default {
minute: "numeric",
}).format(date);
},
fmtTimeAgo: function (date) {
const units = {
year: 24 * 60 * 60 * 1000 * 365,
month: (24 * 60 * 60 * 1000 * 365) / 12,
day: 24 * 60 * 60 * 1000,
hour: 60 * 60 * 1000,
minute: 60 * 1000,
second: 1000,
};

const rtf = new Intl.RelativeTimeFormat("default", { numeric: "auto" });
const elapsed = date - new Date();

// "Math.abs" accounts for both "past" & "future" scenarios
for (var u in units)
if (Math.abs(elapsed) > units[u] || u == "second")
return rtf.format(Math.round(elapsed / units[u]), u);
},
},
};
4 changes: 2 additions & 2 deletions dist/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="EV Charge Controller"><meta name="author" content="andig"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="apple-touch-icon" sizes="180x180" href="ico/apple-touch-icon.png?[[.Version]]"><link rel="icon" type="image/png" sizes="32x32" href="ico/favicon-32x32.png?[[.Version]]"><link rel="icon" type="image/png" sizes="16x16" href="ico/favicon-16x16.png?[[.Version]]"><link rel="manifest" href="ico/site.webmanifest"><link rel="mask-icon" href="ico/safari-pinned-tab.svg?[[.Version]]" color="#18191a"><link rel="shortcut icon" href="ico/favicon.ico?[[.Version]]"><meta name="apple-mobile-web-app-title" content="evcc"><meta name="application-name" content="evcc"><meta name="msapplication-TileColor" content="#18191a"><meta name="msapplication-config" content="ico/browserconfig.xml"><meta name="theme-color" content="#18191a"><title>evcc</title><link href="css/chunk-vendors.882a611f.css" rel="preload" as="style"><link href="css/index.f1264e7c.css" rel="preload" as="style"><link href="js/chunk-vendors.8d9f525d.js" rel="preload" as="script"><link href="js/index.11167e27.js" rel="preload" as="script"><link href="css/chunk-vendors.882a611f.css" rel="stylesheet"><link href="css/index.f1264e7c.css" rel="stylesheet"></head><body><script>window.evcc = {
<!DOCTYPE html><html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="EV Charge Controller"><meta name="author" content="andig"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><link rel="apple-touch-icon" sizes="180x180" href="ico/apple-touch-icon.png?[[.Version]]"><link rel="icon" type="image/png" sizes="32x32" href="ico/favicon-32x32.png?[[.Version]]"><link rel="icon" type="image/png" sizes="16x16" href="ico/favicon-16x16.png?[[.Version]]"><link rel="manifest" href="ico/site.webmanifest"><link rel="mask-icon" href="ico/safari-pinned-tab.svg?[[.Version]]" color="#18191a"><link rel="shortcut icon" href="ico/favicon.ico?[[.Version]]"><meta name="apple-mobile-web-app-title" content="evcc"><meta name="application-name" content="evcc"><meta name="msapplication-TileColor" content="#18191a"><meta name="msapplication-config" content="ico/browserconfig.xml"><meta name="theme-color" content="#18191a"><title>evcc</title><link href="css/chunk-vendors.882a611f.css" rel="preload" as="style"><link href="css/index.f1264e7c.css" rel="preload" as="style"><link href="js/chunk-vendors.8d9f525d.js" rel="preload" as="script"><link href="js/index.ce8c46e1.js" rel="preload" as="script"><link href="css/chunk-vendors.882a611f.css" rel="stylesheet"><link href="css/index.f1264e7c.css" rel="stylesheet"></head><body><script>window.evcc = {
version: "[[.Version]]",
configured: "[[.Configured]]",
};</script><div id="app"></div><script src="js/chunk-vendors.8d9f525d.js"></script><script src="js/index.11167e27.js"></script></body></html>
};</script><div id="app"></div><script src="js/chunk-vendors.8d9f525d.js"></script><script src="js/index.ce8c46e1.js"></script></body></html>
2 changes: 0 additions & 2 deletions dist/js/index.11167e27.js

This file was deleted.

1 change: 0 additions & 1 deletion dist/js/index.11167e27.js.map

This file was deleted.

2 changes: 2 additions & 0 deletions dist/js/index.ce8c46e1.js

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/js/index.ce8c46e1.js.map

Large diffs are not rendered by default.

0 comments on commit eede2e8

Please sign in to comment.