Database initialization wizard

This commit is contained in:
Zaid Abdulla committed 2019-07-11 17:47:36 -07:00
1 parent b51c97e97a
commit 6cb0d0449b
10 files changed
+613 -19

No files matched your search

+3 -6
View File
@@ -65,12 +65,9 @@ This serves the web based user interface. It listens on port 3000 by default.
The argument *--ui-jwt-secret* supplies the key used for signing browser
cookies.
The UI has plenty of configuration options. To populate the an initial sample
configuration, run:
./dist/tools/configure-ui
Use admin/admin credentials to log in.
The UI has plenty of configuration options. When you open GenieACS's UI in a
browser you'll be greeted with a database initialization wizard to help you
populate some initial configuration.
## Support
+1 -1
View File
@@ -169,7 +169,7 @@ async function generateCss(): Promise<void> {
}
async function generateToolsJs(): Promise<void> {
for (const bin of ["configure-ui", "dump-data-model"]) {
for (const bin of ["dump-data-model"]) {
const inputFile = path.resolve(INPUT_DIR, `tools/${bin}`);
const outputFile = path.resolve(OUTPUT_DIR, `tools/${bin}`);
const bundle = await rollup({
+425
View File
@@ -0,0 +1,425 @@
/**
* Copyright 2013-2019 GenieACS Inc.
*
* This file is part of GenieACS.
*
* GenieACS is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* GenieACS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
*/
import * as localCache from "./local-cache";
import { generateSalt, hashPassword } from "./auth";
import * as db from "./ui/db";
import { del } from "./cache";
interface Status {
users: boolean;
presets: boolean;
filters: boolean;
device: boolean;
index: boolean;
overview: boolean;
}
const BOOTSTRAP_SCRIPT = `
const now = Date.now();
// Clear cached data model to force a refresh
clear("Device", now);
clear("InternetGatewayDevice", now);
`.trim();
const DEFAULT_SCRIPT = `
const hourly = Date.now(3600000);
// Refresh basic parameters hourly
declare("InternetGatewayDevice.DeviceInfo.HardwareVersion", {path: hourly, value: hourly});
declare("InternetGatewayDevice.DeviceInfo.SoftwareVersion", {path: hourly, value: hourly});
declare("InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.MACAddress", {path: hourly, value: hourly});
declare("InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.ExternalIPAddress", {path: hourly, value: hourly});
declare("InternetGatewayDevice.LANDevice.*.WLANConfiguration.*.SSID", {path: hourly, value: hourly});
// Don't refresh password field periodically because CPEs always report blank passowrds for security reasons
declare("InternetGatewayDevice.LANDevice.*.WLANConfiguration.*.KeyPassphrase", {path: hourly, value: 1});
declare("InternetGatewayDevice.LANDevice.*.Hosts.Host.*.HostName", {path: hourly, value: hourly});
declare("InternetGatewayDevice.LANDevice.*.Hosts.Host.*.IPAddress", {path: hourly, value: hourly});
declare("InternetGatewayDevice.LANDevice.*.Hosts.Host.*.MACAddress", {path: hourly, value: hourly});
`.trim();
const INFORM_SCRIPT = `
// Device ID as user name
const username = declare("DeviceID.ID", {value: 1}).value[0]
// Password will be fixed a given device because Math.random() is seeded with devcie ID by default.
const password = "" + Math.random();
const informInterval = 300;
// Refresh values daily
const daily = Date.now(86400000);
// Unique inform offset per device for better load distribution
const informTime = daily % 86400000;
declare("InternetGatewayDevice.ManagementServer.ConnectionRequestUsername", {value: daily}, {value: username});
declare("InternetGatewayDevice.ManagementServer.ConnectionRequestPassword", {value: daily}, {value: password});
declare("InternetGatewayDevice.ManagementServer.PeriodicInformEnable", {value: daily}, {value: true});
declare("InternetGatewayDevice.ManagementServer.PeriodicInformInterval", {value: daily}, {value: informInterval});
declare("InternetGatewayDevice.ManagementServer.PeriodicInformTime", {value: daily}, {value: informTime});
declare("Device.ManagementServer.ConnectionRequestUsername", {value: daily}, {value: username});
declare("Device.ManagementServer.ConnectionRequestPassword", {value: daily}, {value: password});
declare("Device.ManagementServer.PeriodicInformEnable", {value: daily}, {value: true});
declare("Device.ManagementServer.PeriodicInformInterval", {value: daily}, {value: informInterval});
declare("Device.ManagementServer.PeriodicInformTime", {value: daily}, {value: informTime});
`.trim();
export async function getStatus(): Promise<Status> {
const configSnapshot = await localCache.getCurrentSnapshot();
const users = localCache.getUsers(configSnapshot);
const presets = localCache.getPresets(configSnapshot);
const ui = localCache.getUiConfig(configSnapshot);
return {
users: !Object.keys(users).length,
presets: !presets.length,
filters: !Object.keys(ui["filters"]).length,
device: !Object.keys(ui["device"]).length,
index: !Object.keys(ui["index"]).length,
overview: !Object.keys(ui["overview"]).length
};
}
export async function seed(options): Promise<void> {
const resources = {};
const proms = [];
if (options.users) {
resources["permissions"] = [
{ role: "admin", resource: "devices", access: 3, validate: "true" },
{ role: "admin", resource: "faults", access: 3, validate: "true" },
{ role: "admin", resource: "files", access: 3, validate: "true" },
{ role: "admin", resource: "presets", access: 3, validate: "true" },
{ role: "admin", resource: "provisions", access: 3, validate: "true" },
{ role: "admin", resource: "config", access: 3, validate: "true" },
{ role: "admin", resource: "permissions", access: 3, validate: "true" },
{ role: "admin", resource: "users", access: 3, validate: "true" },
{
role: "admin",
resource: "virtualParameters",
access: 3,
validate: "true"
}
];
resources["users"] = [
{ username: "admin", password: "admin", roles: ["admin"] }
];
}
if (options.filters) {
resources["config"] = (resources["config"] || []).concat([
{ _id: "ui.filters.0.label", value: "'Serial number'" },
{ _id: "ui.filters.0.parameter", value: "DeviceID.SerialNumber" },
{ _id: "ui.filters.0.type", value: "'string'" },
{ _id: "ui.filters.1.label", value: "'Product class'" },
{ _id: "ui.filters.1.parameter", value: "DeviceID.ProductClass" },
{ _id: "ui.filters.1.type", value: "'string'" },
{ _id: "ui.filters.2.label", value: "'Tag'" },
{ _id: "ui.filters.2.parameter", value: "tag" },
{ _id: "ui.filters.2.type", value: "'string'" }
]);
}
if (options.device) {
resources["config"] = (resources["config"] || []).concat([
{ _id: "ui.device.0.type", value: "'tags'" },
{ _id: "ui.device.1.type", value: "'ping'" },
{ _id: "ui.device.2.type", value: "'parameter-list'" },
{ _id: "ui.device.2.parameters.0.type", value: "'container'" },
{ _id: "ui.device.2.parameters.0.element", value: "'span.inform'" },
{ _id: "ui.device.2.parameters.0.label", value: "'Last inform'" },
{
_id: "ui.device.2.parameters.0.components.0.type",
value: "'parameter'"
},
{ _id: "ui.device.2.parameters.0.components.1.chart", value: "'online'" },
{
_id: "ui.device.2.parameters.0.components.1.type",
value: "'overview-dot'"
},
{
_id: "ui.device.2.parameters.0.components.2.type",
value: "'summon-button'"
},
{
_id: "ui.device.2.parameters.0.components.2.parameters.0",
value: "InternetGatewayDevice.DeviceInfo.HardwareVersion"
},
{
_id: "ui.device.2.parameters.0.components.2.parameters.1",
value: "InternetGatewayDevice.DeviceInfo.SoftwareVersion"
},
{
_id: "ui.device.2.parameters.0.components.2.parameters.2",
value:
"InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.MACAddress"
},
{
_id: "ui.device.2.parameters.0.components.2.parameters.3",
value:
"InternetGatewayDevice.WANDevice.*.WANConnectionDevice.*.WANIPConnection.*.ExternalIPAddress"
},
{
_id: "ui.device.2.parameters.0.components.2.parameters.4",
value: "InternetGatewayDevice.LANDevice.*.WLANConfiguration.*.SSID"
},
{
_id: "ui.device.2.parameters.0.components.2.parameters.5",
value:
"InternetGatewayDevice.LANDevice.*.WLANConfiguration.*.KeyPassphrase"
},
{
_id: "ui.device.2.parameters.0.components.2.parameters.6",
value: "InternetGatewayDevice.LANDevice.*.Hosts.Host.*.HostName"
},
{
_id: "ui.device.2.parameters.0.components.2.parameters.7",
value: "InternetGatewayDevice.LANDevice.*.Hosts.Host.*.IPAddress"
},
{
_id: "ui.device.2.parameters.0.components.2.parameters.8",
value: "InternetGatewayDevice.LANDevice.*.Hosts.Host.*.MACAddress"
},
{
_id: "ui.device.2.parameters.0.parameter",
value: "DATE_STRING(Events.Inform)"
},
{ _id: "ui.device.2.parameters.1.label", value: "'Serial number'" },
{
_id: "ui.device.2.parameters.1.parameter",
value: "DeviceID.SerialNumber"
},
{ _id: "ui.device.2.parameters.2.label", value: "'Product class'" },
{
_id: "ui.device.2.parameters.2.parameter",
value: "DeviceID.ProductClass"
},
{ _id: "ui.device.2.parameters.3.label", value: "'OUI'" },
{
_id: "ui.device.2.parameters.3.parameter",
value: "DeviceID.OUI"
},
{ _id: "ui.device.2.parameters.4.label", value: "'Manufacturer'" },
{
_id: "ui.device.2.parameters.4.parameter",
value: "DeviceID.Manufacturer"
},
{ _id: "ui.device.2.parameters.5.label", value: "'Hardware version'" },
{
_id: "ui.device.2.parameters.5.parameter",
value: "InternetGatewayDevice.DeviceInfo.HardwareVersion"
},
{ _id: "ui.device.2.parameters.6.label", value: "'Software version'" },
{
_id: "ui.device.2.parameters.6.parameter",
value: "InternetGatewayDevice.DeviceInfo.SoftwareVersion"
},
{ _id: "ui.device.2.parameters.7.label", value: "'MAC'" },
{
_id: "ui.device.2.parameters.7.parameter",
value:
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.MACAddress"
},
{ _id: "ui.device.2.parameters.8.label", value: "'IP'" },
{
_id: "ui.device.2.parameters.8.parameter",
value:
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress"
},
{ _id: "ui.device.2.parameters.9.label", value: "'WLAN SSID'" },
{
_id: "ui.device.2.parameters.9.parameter",
value: "InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID"
},
{ _id: "ui.device.2.parameters.10.label", value: "'WLAN passphrase'" },
{
_id: "ui.device.2.parameters.10.parameter",
value:
"InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.KeyPassphrase"
},
{ _id: "ui.device.3.type", value: "'parameter-table'" },
{ _id: "ui.device.3.label", value: "'WLAN hosts'" },
{
_id: "ui.device.3.parameter",
value: "InternetGatewayDevice.LANDevice.1.Hosts.Host"
},
{ _id: "ui.device.3.childParameters.0.label", value: "'Host name'" },
{ _id: "ui.device.3.childParameters.0.parameter", value: "HostName" },
{ _id: "ui.device.3.childParameters.1.label", value: "'IP address'" },
{ _id: "ui.device.3.childParameters.1.parameter", value: "IPAddress" },
{ _id: "ui.device.3.childParameters.2.label", value: "'MAC address'" },
{ _id: "ui.device.3.childParameters.2.parameter", value: "MACAddress" },
{ _id: "ui.device.4.type", value: "'container'" },
{ _id: "ui.device.4.element", value: "'div'" },
{ _id: "ui.device.4.components.0.components.0", value: "'Faults'" },
{ _id: "ui.device.4.components.0.element", value: "'h3'" },
{ _id: "ui.device.4.components.0.type", value: "'container'" },
{ _id: "ui.device.4.components.1.type", value: "'device-faults'" },
{ _id: "ui.device.5.type", value: "'container'" },
{ _id: "ui.device.5.element", value: "'div.container-full-width'" },
{
_id: "ui.device.5.components.0.components.0",
value: "'All parameters'"
},
{ _id: "ui.device.5.components.0.element", value: "'h3'" },
{ _id: "ui.device.5.components.0.type", value: "'container'" },
{ _id: "ui.device.5.components.1.type", value: "'all-parameters'" },
{ _id: "ui.device.6.type", value: "'device-actions'" }
]);
}
if (options.index) {
resources["config"] = (resources["config"] || []).concat([
{ _id: "ui.index.0.type", value: "'device-link'" },
{ _id: "ui.index.0.label", value: "'Serial number'" },
{ _id: "ui.index.0.parameter", value: "DeviceID.SerialNumber" },
{ _id: "ui.index.0.components.0.type", value: "'parameter'" },
{ _id: "ui.index.1.label", value: "'Product class'" },
{ _id: "ui.index.1.parameter", value: "DeviceID.ProductClass" },
{ _id: "ui.index.2.label", value: "'Software version'" },
{
_id: "ui.index.2.parameter",
value: "InternetGatewayDevice.DeviceInfo.SoftwareVersion"
},
{ _id: "ui.index.3.label", value: "'IP'" },
{
_id: "ui.index.3.parameter",
value:
"InternetGatewayDevice.WANDevice.1.WANConnectionDevice.1.WANIPConnection.1.ExternalIPAddress"
},
{ _id: "ui.index.4.label", value: "'SSID'" },
{
_id: "ui.index.4.parameter",
value: "InternetGatewayDevice.LANDevice.1.WLANConfiguration.1.SSID"
},
{ _id: "ui.index.5.type", value: "'container'" },
{ _id: "ui.index.5.label", value: "'Last inform'" },
{ _id: "ui.index.5.element", value: "'span.inform'" },
{ _id: "ui.index.5.parameter", value: "DATE_STRING(Events.Inform)" },
{ _id: "ui.index.5.components.0.type", value: "'parameter'" },
{ _id: "ui.index.5.components.1.chart", value: "'online'" },
{ _id: "ui.index.5.components.1.type", value: "'overview-dot'" },
{ _id: "ui.index.6.type", value: "'tags'" },
{ _id: "ui.index.6.label", value: "'Tags'" },
{ _id: "ui.index.6.parameter", value: "Tags" },
{ _id: "ui.index.6.unsortable", value: "true" },
{ _id: "ui.index.6.writable", value: "false" }
]);
}
if (options.overview) {
resources["config"] = (resources["config"] || []).concat([
{ _id: "ui.overview.charts.online.label", value: "'Online status'" },
{
_id: "ui.overview.charts.online.slices.1_onlineNow.color",
value: "'#31a354'"
},
{
_id: "ui.overview.charts.online.slices.1_onlineNow.filter",
value: "Events.Inform > NOW() - 5 * 60 * 1000"
},
{
_id: "ui.overview.charts.online.slices.1_onlineNow.label",
value: "'Online now'"
},
{
_id: "ui.overview.charts.online.slices.2_past24.color",
value: "'#a1d99b'"
},
{
_id: "ui.overview.charts.online.slices.2_past24.filter",
value:
"Events.Inform > (NOW() - 5 * 60 * 1000) - (24 * 60 * 60 * 1000) AND Events.Inform < (NOW() - 5 * 60 * 1000)"
},
{
_id: "ui.overview.charts.online.slices.2_past24.label",
value: "'Past 24 hours'"
},
{
_id: "ui.overview.charts.online.slices.3_others.color",
value: "'#e5f5e0'"
},
{
_id: "ui.overview.charts.online.slices.3_others.filter",
value: "Events.Inform < (NOW() - 5 * 60 * 1000) - (24 * 60 * 60 * 1000)"
},
{
_id: "ui.overview.charts.online.slices.3_others.label",
value: "'Others'"
},
{ _id: "ui.overview.groups.online.label", value: "''" },
{ _id: "ui.overview.groups.online.charts.0", value: "'online'" }
]);
}
if (options.presets) {
resources["presets"] = [
{
_id: "bootstrap",
weight: 0,
channel: "bootstrap",
provision: "bootstrap"
},
{ _id: "default", weight: 0, channel: "default", provision: "default" },
{ _id: "inform", weight: 0, channel: "inform", provision: "inform" }
];
resources["provisions"] = [
{ _id: "bootstrap", script: BOOTSTRAP_SCRIPT },
{ _id: "default", script: DEFAULT_SCRIPT },
{ _id: "inform", script: INFORM_SCRIPT }
];
}
if (resources["permissions"]) {
for (const p of resources["permissions"]) {
p["_id"] = `${p["role"]}:${p["resource"]}:${p["access"]}`;
proms.push(db.putPermission(p["_id"], p));
}
}
if (resources["users"]) {
for (const u of resources["users"]) {
u["salt"] = await generateSalt(64);
u["password"] = await hashPassword(u["password"], u["salt"]);
u["roles"] = (u["roles"] || []).join(",");
u["_id"] = u["username"];
delete u["username"];
proms.push(db.putUser(u["_id"], u));
}
}
if (resources["provisions"]) {
for (const p of resources["provisions"])
proms.push(db.putProvision(p["_id"], p));
}
if (resources["presets"])
for (const p of resources["presets"]) proms.push(db.putPreset(p["_id"], p));
if (resources["config"])
for (const c of resources["config"]) proms.push(db.putConfig(c["_id"], c));
await proms;
return del("presets_hash");
}
+1 -10
View File
@@ -340,7 +340,7 @@ async function fetchConfig(): Promise<[{}, {}]> {
filters: {},
device: {},
index: {},
overview: { charts: {}, groups: {} }
overview: {}
};
const _config = {};
@@ -362,15 +362,6 @@ async function fetchConfig(): Promise<[{}, {}]> {
}
}
if (!Object.keys(ui["index"]).length) {
ui["index"] = {
"0": {
label: "ID",
parameter: ["PARAM", "DeviceID.ID"]
}
};
}
return [_config, ui];
}
+48 -1
View File
@@ -32,6 +32,7 @@ import * as logger from "./logger";
import * as localCache from "./local-cache";
import { PermissionSet } from "./types";
import { authSimple } from "./ui/api-functions";
import * as init from "./init";
declare module "koa" {
interface Request {
@@ -142,11 +143,57 @@ koa.use(async (ctx, next) => {
koa.use(koaBodyParser());
router.use("/api", api.routes(), api.allowedMethods());
router.get("/init", async ctx => {
const status = await init.getStatus();
if (Object.keys(localCache.getUsers(ctx.state.configSnapshot)).length) {
if (!ctx.state.authorizer.hasAccess("users", 3)) status["users"] = false;
if (!ctx.state.authorizer.hasAccess("permissions", 3))
status["users"] = false;
if (!ctx.state.authorizer.hasAccess("config", 3)) {
status["filters"] = false;
status["device"] = false;
status["index"] = false;
status["overview"] = false;
}
if (!ctx.state.authorizer.hasAccess("presets", 3))
status["presets"] = false;
if (!ctx.state.authorizer.hasAccess("provisions", 3))
status["presets"] = false;
}
ctx.body = status;
});
router.post("/init", async ctx => {
const status = ctx.request.body;
if (Object.keys(localCache.getUsers(ctx.state.configSnapshot)).length) {
if (!ctx.state.authorizer.hasAccess("users", 3)) status["users"] = false;
if (!ctx.state.authorizer.hasAccess("permissions", 3))
status["users"] = false;
if (!ctx.state.authorizer.hasAccess("config", 3)) {
status["filters"] = false;
status["device"] = false;
status["index"] = false;
status["overview"] = false;
}
if (!ctx.state.authorizer.hasAccess("presets", 3))
status["presets"] = false;
if (!ctx.state.authorizer.hasAccess("provisions", 3))
status["presets"] = false;
}
await init.seed(status);
ctx.body = "";
});
router.get("/", async ctx => {
let permissionSets = [];
if (ctx.state.user && ctx.state.user.username)
permissionSets = getPermissionSets(ctx);
let wizard = "";
if (!Object.keys(localCache.getUsers(ctx.state.configSnapshot)).length)
wizard = '<script>window.location.hash = "#!/wizard";</script>';
ctx.body = `
<html>
<head>
@@ -165,7 +212,7 @@ router.get("/", async ctx => {
)};
window.permissionSets = ${JSON.stringify(permissionSets)};
</script>
<script src="app.js"></script>
<script src="app.js"></script>${wizard}
</body>
</html>
`;
+2
View File
@@ -20,6 +20,7 @@
import m, { RouteResolver } from "mithril";
import layout from "./layout";
import * as store from "./store";
import * as wizardPage from "./wizard-page";
import * as loginPage from "./login-page";
import * as overviewPage from "./overview-page";
import * as devicesPage from "./devices-page";
@@ -136,6 +137,7 @@ function redirectAdminPage(): RouteResolver {
}
m.route(document.body, "/overview", {
"/wizard": pagify("wizard", wizardPage),
"/login": pagify("login", loginPage),
"/overview": pagify("overview", overviewPage),
"/devices": pagify("devices", devicesPage),
+9
View File
@@ -716,3 +716,12 @@ span.parameter-value {
color: #aaa;
}
}
.wizard-dialog {
max-width: 720px;
margin: 10px auto;
padding: 10px;
border-radius: 6px;
border: 1px solid var(--color1);
box-shadow: 0 0 10px #ccc;
}
+6
View File
@@ -69,6 +69,12 @@ export function init(args): Promise<{}> {
const filter = args.hasOwnProperty("filter") ? "" + args["filter"] : "";
const sort = args.hasOwnProperty("sort") ? "" + args["sort"] : "";
const indexParameters = Object.values(config.ui.index);
if (!indexParameters.length) {
indexParameters.push({
label: "ID",
parameter: ["PARAM", "DeviceID.ID"]
});
}
resolve({ filter, indexParameters, sort });
});
}
+1 -1
View File
@@ -23,7 +23,7 @@ import config from "./config";
import * as store from "./store";
import pieChartComponent from "./pie-chart-component";
const GROUPS = config.ui.overview.groups;
const GROUPS = config.ui.overview.groups || {};
const CHARTS = {};
for (const group of Object.values(GROUPS)) {
for (const chartName of Object.values(group["charts"]) as string[])
+117
View File
@@ -0,0 +1,117 @@
/**
* Copyright 2013-2019 GenieACS Inc.
*
* This file is part of GenieACS.
*
* GenieACS is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* GenieACS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
*/
import m, { ClosureComponent, Component } from "mithril";
import * as notifications from "./notifications";
export async function init(): Promise<{}> {
return m.request({ url: "/init" });
}
export const component: ClosureComponent = (vnode): Component => {
let options = vnode.attrs;
const selected = new Set();
for (const [k, v] of Object.entries(options)) if (v) selected.add(k);
return {
view: () => {
document.title = "Initialization wizard - GenieACS";
const checkboxes = [
"users",
"presets",
"filters",
"device",
"index",
"overview"
].map(s => {
if (!options[s]) selected.delete(s);
return m("input", {
type: "checkbox",
checked: selected.has(s),
disabled: !options[s],
style: "display: inline; margin-right: 0.5em;",
onclick: e => {
if (e.target.checked) selected.add(s);
else selected.delete(s);
}
});
});
return m(".wizard-dialog", [
m("h1", "Initialization wizard"),
m(
"p",
"This wizard will seed the database with a minimal initial configuration to serve as a starting point. Select what you want to initialize and click 'ABRACADABRA!'."
),
m("div", m("label", checkboxes[0], "Users, roles and permissions")),
m("div", m("label", checkboxes[1], "Presets and provisions")),
m(
"div",
m("label", checkboxes[2], "Devices predefined search filters")
),
m("div", m("label", checkboxes[3], "Device details page")),
m("div", m("label", checkboxes[4], "Devices listing page")),
m("div", m("label", checkboxes[5], "Overview page")),
m(
"button.primary",
{
style: "margin: 10px;",
disabled: selected.size === 0,
onclick: e => {
e.target.disabled = true;
const opts = {};
for (const s of selected) opts[s] = true;
m.request({
method: "POST",
url: "/init",
data: opts
})
.then(() => {
setTimeout(() => {
m.request({ url: "/init" }).then(o => {
e.target.disabled = false;
options = o;
notifications.push("success", "Initialization complete", {
"Open Sesame!": () => {
m.route.set("/login");
window.location.reload();
}
});
});
}, 3000);
if (opts["users"]) {
alert(
"An administrator user has been created for you. Use admin/admin to log in. Don't forget to change the default password."
);
}
})
.catch(err => {
notifications.push("error", err.message);
});
}
},
"ABRACADABRA!"
)
]);
}
};
};