signalk-czone 0.3.0-beta.17 → 0.3.0-beta.18
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 +5 -0
- package/package.json +1 -1
- package/public/index.html +53 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0-beta.18
|
|
4
|
+
|
|
5
|
+
- Adds in-page Signal K sign-in for browser and installed home-screen apps, without leaving CZone (#35, thanks @superstar76).
|
|
6
|
+
- Remembers login across app restarts, preserves the form during refreshes, and shows clear login errors with the Admin UI login retained as a fallback.
|
|
7
|
+
|
|
3
8
|
## 0.3.0-beta.17
|
|
4
9
|
|
|
5
10
|
- Prompts for Signal K login when CZone circuit requests are unauthorized, returning to the webapp after sign-in (#34).
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -75,6 +75,12 @@
|
|
|
75
75
|
.hero h1, .hero p { position:relative; z-index:1; }
|
|
76
76
|
.hero h1 { margin:0; font-size:30px; line-height:1.15; letter-spacing:-.7px; }
|
|
77
77
|
.hero p { margin:9px 0 0; color:#a9c2d9; font-size:14px; }
|
|
78
|
+
.login-form { display:grid; gap:8px; max-width:280px; margin:10px 0; }
|
|
79
|
+
.login-form input { padding:10px 12px; border-radius:10px; border:1px solid var(--line); background:rgba(255,255,255,.05); color:var(--text); font-size:16px; }
|
|
80
|
+
.login-form button { padding:10px 12px; border-radius:10px; border:0; background:linear-gradient(135deg,#168eea,#2164b8); color:#fff; font-weight:700; font-size:15px; cursor:pointer; }
|
|
81
|
+
.login-form button:disabled { opacity:.6; cursor:default; }
|
|
82
|
+
.login-form .login-error { color:#ff8a9a; font-size:13px; }
|
|
83
|
+
.login-form .login-error:empty { display:none; }
|
|
78
84
|
.search { position:relative; }
|
|
79
85
|
.search input { width:100%; border:1px solid var(--line); background:#0b1d30; color:white; border-radius:999px; padding:11px 15px 11px 38px; outline:none; }
|
|
80
86
|
.search input:focus { border-color:rgba(56,169,255,.65); box-shadow:0 0 0 3px rgba(56,169,255,.10); }
|
|
@@ -702,13 +708,17 @@
|
|
|
702
708
|
}
|
|
703
709
|
function showLoadError(message, signIn) {
|
|
704
710
|
const el = document.querySelector('#loadError');
|
|
711
|
+
// Keep a sign-in form that is already showing: someone may be typing in it.
|
|
712
|
+
if (signIn && !el.hidden && el.loginForm) return;
|
|
713
|
+
el.loginForm = null;
|
|
705
714
|
el.textContent = message + ' ';
|
|
715
|
+
if (signIn) el.appendChild(loginForm(el));
|
|
706
716
|
const link = document.createElement('a');
|
|
707
717
|
link.style.color = 'var(--cyan)';
|
|
708
718
|
if (signIn) {
|
|
709
719
|
const here = window.location.pathname + window.location.search + window.location.hash;
|
|
710
720
|
link.href = '/admin/#/login?redirect=' + encodeURIComponent(here);
|
|
711
|
-
link.textContent = '
|
|
721
|
+
link.textContent = 'Or sign in on the Signal K login page';
|
|
712
722
|
} else {
|
|
713
723
|
link.href = window.location.href;
|
|
714
724
|
link.textContent = 'Retry';
|
|
@@ -718,6 +728,46 @@
|
|
|
718
728
|
el.hidden = false;
|
|
719
729
|
}
|
|
720
730
|
|
|
731
|
+
// Sign in on the page itself. A home-screen app (iPad, Android) keeps its
|
|
732
|
+
// own login, separate from the browser's, and has no address bar; the link
|
|
733
|
+
// to the admin page stays as the alternative. "Remember me" keeps the login
|
|
734
|
+
// after the app is closed, for as long as Signal K's token lasts.
|
|
735
|
+
function loginForm(banner) {
|
|
736
|
+
const form = document.createElement('form');
|
|
737
|
+
form.className = 'login-form';
|
|
738
|
+
const field = (name, type, autocomplete, placeholder) => {
|
|
739
|
+
const input = document.createElement('input');
|
|
740
|
+
input.name = name; input.type = type; input.required = true;
|
|
741
|
+
input.autocomplete = autocomplete; input.placeholder = placeholder;
|
|
742
|
+
form.appendChild(input);
|
|
743
|
+
return input;
|
|
744
|
+
};
|
|
745
|
+
const user = field('username', 'text', 'username', 'Signal K user');
|
|
746
|
+
const pass = field('password', 'password', 'current-password', 'Password');
|
|
747
|
+
const button = document.createElement('button');
|
|
748
|
+
button.type = 'submit'; button.textContent = 'Log in';
|
|
749
|
+
form.appendChild(button);
|
|
750
|
+
const error = document.createElement('span');
|
|
751
|
+
error.className = 'login-error';
|
|
752
|
+
form.appendChild(error);
|
|
753
|
+
form.onsubmit = async event => {
|
|
754
|
+
event.preventDefault();
|
|
755
|
+
error.textContent = '';
|
|
756
|
+
button.disabled = true;
|
|
757
|
+
try {
|
|
758
|
+
const r = await fetch('/signalk/v1/auth/login', { method:'POST', credentials:'include', headers:{ 'Content-Type':'application/json' },
|
|
759
|
+
body: JSON.stringify({ username: user.value, password: pass.value, rememberMe: true }) });
|
|
760
|
+
if (r.ok) { window.location.reload(); return; }
|
|
761
|
+
error.textContent = r.status === 401 ? 'Wrong user name or password.' : 'Signal K refused the login (HTTP ' + r.status + ').';
|
|
762
|
+
} catch (_) {
|
|
763
|
+
error.textContent = 'Signal K could not be reached.';
|
|
764
|
+
}
|
|
765
|
+
button.disabled = false;
|
|
766
|
+
};
|
|
767
|
+
banner.loginForm = form;
|
|
768
|
+
return form;
|
|
769
|
+
}
|
|
770
|
+
|
|
721
771
|
async function showCircuitRequestError(response) {
|
|
722
772
|
let signIn = response.status === 401;
|
|
723
773
|
if (response.status === 403) {
|
|
@@ -732,7 +782,8 @@
|
|
|
732
782
|
? 'Signal K denied access to CZone circuits. Your account may not have the required permissions.'
|
|
733
783
|
: 'Could not load CZone circuits (HTTP ' + response.status + '). Check the Signal K server and CZone plugin.';
|
|
734
784
|
showLoadError(message, signIn);
|
|
735
|
-
|
|
785
|
+
// The plotter hides the banner, and its login is the Navico embedder's token.
|
|
786
|
+
updateSocketIndicator(signIn ? (MFD ? 'Sign in required: set the token in the Navico embedder' : 'Sign in required') : 'Unable to load CZone circuits', false);
|
|
736
787
|
}
|
|
737
788
|
|
|
738
789
|
async function refreshOnce(reason = 'manual') {
|