@scalio-cloud/ui 0.31.0 → 0.32.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/README.md +5 -1
- package/auth.css +1 -1
- package/package.json +1 -1
- package/react/labels.js +6 -0
- package/react/maintenance.js +19 -2
package/README.md
CHANGED
|
@@ -319,9 +319,13 @@ sorts the group `system` that way). The reset block talks to scalio-platform `fa
|
|
|
319
319
|
import { FactoryReset, factoryResetApi, SettingsField, SettingsRow } from "@scalio-cloud/ui/react";
|
|
320
320
|
|
|
321
321
|
const reset = factoryResetApi(api); // once, outside the component
|
|
322
|
-
<FactoryReset client={reset} lang={lang} tokenKey="citadel_token" backupTo="/settings/backup" link={Link} />
|
|
322
|
+
<FactoryReset client={reset} lang={lang} tokenKey="citadel_token" backupTo="/settings/backup" accountTo="/profile" link={Link} />
|
|
323
323
|
```
|
|
324
324
|
|
|
325
|
+
Since 0.32.0 (N21, security review 2026-10-27) the reset needs the code of the signed-in admin's authenticator app
|
|
326
|
+
or a backup code (`code` in the request, scalio-platform 0.11.0). Without a second factor the block says so and links
|
|
327
|
+
to `accountTo` (the profile page) instead of allowing the reset.
|
|
328
|
+
|
|
325
329
|
`SettingsField` (label, field, help) and `SettingsRow` (title and help left, a switch or button right; `tone="danger"`)
|
|
326
330
|
keep the fields inside a `SettingsSection` the same in every app.
|
|
327
331
|
|
package/auth.css
CHANGED
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
padding: 1.5rem 0; border-top: 1px solid hsl(var(--border));
|
|
103
103
|
}
|
|
104
104
|
.scalio-profile-section:first-of-type { border-top: 0; padding-top: 0; }
|
|
105
|
-
@media (min-width: 768px) { .scalio-profile-section { grid-template-columns: minmax(0, 1fr) minmax(0,
|
|
105
|
+
@media (min-width: 768px) { .scalio-profile-section { grid-template-columns: minmax(0, 1fr) minmax(0, 3fr); gap: 2rem; } }
|
|
106
106
|
.scalio-profile-section-title {
|
|
107
107
|
margin: 0; font-family: 'Chivo', sans-serif; font-weight: 900; font-size: 0.875rem;
|
|
108
108
|
text-transform: uppercase; letter-spacing: 0.02em;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalio-cloud/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Scalio Control Room design tokens, Tailwind preset, self-hosted fonts, the shared app header, sign-in layout, sidebar and page blocks",
|
|
5
5
|
"license": "SEE LICENSE IN README.md",
|
|
6
6
|
"private": false,
|
package/react/labels.js
CHANGED
|
@@ -336,6 +336,9 @@ const LABELS = {
|
|
|
336
336
|
removeLicense: "Lizenz ebenfalls entfernen",
|
|
337
337
|
removeLicenseHint: "Danach läuft die Instanz als freie Edition, bis wieder ein Lizenzschlüssel eingetragen ist. Die Installations-ID bleibt.",
|
|
338
338
|
password: "Ihr Passwort",
|
|
339
|
+
code: "Code aus der Authenticator-App oder Backup-Code",
|
|
340
|
+
noFactor: "Zum Zurücksetzen braucht Ihr Konto eine Authenticator-App; richten Sie sie zuerst im Profil ein. Ein Konto, das sich nur mit Microsoft anmeldet, kann nicht zurücksetzen: Das macht ein lokaler Admin mit Authenticator-App.",
|
|
341
|
+
setUpFactor: "Zum Profil",
|
|
339
342
|
run: "Auf Werkseinstellungen zurücksetzen",
|
|
340
343
|
},
|
|
341
344
|
license: {
|
|
@@ -744,6 +747,9 @@ const LABELS = {
|
|
|
744
747
|
removeLicense: "Remove the license as well",
|
|
745
748
|
removeLicenseHint: "Afterwards the instance runs as the free edition until a license key is entered again. The installation ID stays.",
|
|
746
749
|
password: "Your password",
|
|
750
|
+
code: "Code from the authenticator app or a backup code",
|
|
751
|
+
noFactor: "To reset, your account needs an authenticator app; set it up in your profile first. An account that signs in only with Microsoft cannot reset: a local admin with an authenticator app does it.",
|
|
752
|
+
setUpFactor: "Go to profile",
|
|
747
753
|
run: "Reset to factory settings",
|
|
748
754
|
},
|
|
749
755
|
license: {
|
package/react/maintenance.js
CHANGED
|
@@ -32,6 +32,7 @@ function FactoryReset(props) {
|
|
|
32
32
|
const [info, setInfo] = React.useState(null);
|
|
33
33
|
const [confirm, setConfirm] = React.useState("");
|
|
34
34
|
const [password, setPassword] = React.useState("");
|
|
35
|
+
const [code, setCode] = React.useState("");
|
|
35
36
|
const [removeLicense, setRemoveLicense] = React.useState(false);
|
|
36
37
|
const [busy, setBusy] = React.useState(false);
|
|
37
38
|
const [error, setError] = React.useState("");
|
|
@@ -42,14 +43,17 @@ function FactoryReset(props) {
|
|
|
42
43
|
return () => { alive = false; };
|
|
43
44
|
}, [client]);
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
// N21: the backend says second_factor true (code needed) or false (set one up first); an older backend says nothing.
|
|
47
|
+
const factor = info ? info.second_factor : undefined;
|
|
48
|
+
const ready = confirm.trim() === "RESET" && (!info || !info.password || !!password)
|
|
49
|
+
&& factor !== false && (factor !== true || !!code.trim());
|
|
46
50
|
const run = async (e) => {
|
|
47
51
|
e.preventDefault();
|
|
48
52
|
if (!ready) return;
|
|
49
53
|
setBusy(true);
|
|
50
54
|
setError("");
|
|
51
55
|
try {
|
|
52
|
-
await client.run({ confirm, password, remove_license: removeLicense });
|
|
56
|
+
await client.run({ confirm, password, code, remove_license: removeLicense });
|
|
53
57
|
try { if (props.tokenKey) window.localStorage.removeItem(props.tokenKey); } catch (x) { /* private mode */ }
|
|
54
58
|
if (props.onDone) props.onDone();
|
|
55
59
|
else window.location.href = "/login";
|
|
@@ -94,6 +98,19 @@ function FactoryReset(props) {
|
|
|
94
98
|
h("input", { id: "factory-reset-password", type: "password", className: "scalio-input", value: password, disabled: busy,
|
|
95
99
|
autoComplete: "current-password", "data-testid": "factory-reset-password", onChange: (e) => setPassword(e.target.value) }))
|
|
96
100
|
: null,
|
|
101
|
+
factor === true
|
|
102
|
+
? h(Field, { id: "factory-reset-code", label: L.code },
|
|
103
|
+
h("input", { id: "factory-reset-code", className: "scalio-input", value: code, disabled: busy, inputMode: "numeric",
|
|
104
|
+
autoComplete: "one-time-code", "data-testid": "factory-reset-code", onChange: (e) => setCode(e.target.value) }))
|
|
105
|
+
: null,
|
|
106
|
+
factor === false
|
|
107
|
+
? h("div", { className: "scalio-notice is-warn", "data-testid": "factory-reset-no-factor" },
|
|
108
|
+
h("span", null, L.noFactor),
|
|
109
|
+
props.accountTo && info.password
|
|
110
|
+
? h(props.link || "a", Object.assign({ className: "scalio-btn" },
|
|
111
|
+
props.link ? { to: props.accountTo } : { href: props.accountTo }), L.setUpFactor)
|
|
112
|
+
: null)
|
|
113
|
+
: null,
|
|
97
114
|
error ? h("div", { className: "scalio-notice is-error", role: "alert", "data-testid": "factory-reset-error" }, error) : null,
|
|
98
115
|
h("div", { className: "scalio-settings-section-footer" },
|
|
99
116
|
h("button", { type: "submit", className: "scalio-btn is-danger is-solid", disabled: busy || !ready, "data-testid": "factory-reset-run" },
|