112 lines
4.5 KiB
JavaScript
112 lines
4.5 KiB
JavaScript
// lib/configWorkflow.js
|
|
// The presence of configuration_workflow is the single switch that makes every
|
|
// facility (headers/routes/layout) a (cfg)=>value factory (ARCHITECTURE.md 3.1/5.1).
|
|
// This workflow mounts:
|
|
// (1) an informational step linking to the builder SPA (URL_PREFIX + "/editor"), and
|
|
// (2) the layoutMode toggle, HARD-BLOCKED unless layout_by_role covers every live
|
|
// role so the last-installed fallback is never the live selector and per-request
|
|
// overlay suppression stays deterministic (ARCHITECTURE.md 5.7 / 12.3).
|
|
const Workflow = require("@saltcorn/data/models/workflow");
|
|
const Form = require("@saltcorn/data/models/form");
|
|
const Role = require("@saltcorn/data/models/role");
|
|
const { getState } = require("@saltcorn/data/db/state");
|
|
const { PLUGIN_NAME, URL_PREFIX, CFG } = require("./constants");
|
|
|
|
const EDITOR_URL = URL_PREFIX + "/editor";
|
|
|
|
|
|
// Every role row in _sc_roles is a "live" role. A role is covered when
|
|
// layout_by_role names theme-builder for it (keys are JSON strings, role.id is
|
|
// numeric -> normalize to String on both sides). Returns the list of uncovered
|
|
// role names; empty means full coverage (ARCHITECTURE.md 5.7 / 12.3).
|
|
async function uncoveredRoles() {
|
|
const byRole = getState().getConfig("layout_by_role", {}) || {};
|
|
const roles = await Role.find({}, { orderBy: "id" });
|
|
const out = [];
|
|
for (const role of roles) {
|
|
const mapped = byRole[role.id] != null ? byRole[role.id] : byRole[String(role.id)];
|
|
if (mapped !== PLUGIN_NAME) {
|
|
out.push(role.role);
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
|
|
function configuration_workflow() {
|
|
return new Workflow({
|
|
steps: [
|
|
{
|
|
name: "Theme builder",
|
|
form: async () =>
|
|
new Form({
|
|
blurb:
|
|
"Design and manage themes in the visual builder, then activate one " +
|
|
"from the theme list. The builder opens in a full-page editor.",
|
|
fields: [
|
|
{
|
|
name: "_builder_link",
|
|
label: "Open the builder",
|
|
input_type: "custom_html",
|
|
attributes: {
|
|
html:
|
|
'<a class="btn btn-primary" target="_blank" rel="noopener" href="' +
|
|
EDITOR_URL +
|
|
'">Open theme builder »</a>',
|
|
},
|
|
},
|
|
],
|
|
}),
|
|
},
|
|
{
|
|
name: "Layout mode",
|
|
form: async () => {
|
|
// Resolve coverage up front so the (synchronous) form validator can
|
|
// hard-block enabling layoutMode when any live role is uncovered.
|
|
const uncovered = await uncoveredRoles();
|
|
return new Form({
|
|
blurb:
|
|
"By default theme-builder only RECOLORS your current theme (a CSS " +
|
|
"overlay on top of your active layout). Turn this on to let " +
|
|
"theme-builder provide the PAGE LAYOUT itself (navbar / sidebar / " +
|
|
"content), making it a selectable site layout. It stays off until " +
|
|
"you opt in so that installing the plugin never changes your site's " +
|
|
"layout (Saltcorn uses the last-installed layout as the default). " +
|
|
"When on, assign theme-builder to roles under 'layout by role'; it " +
|
|
"must cover every role before this can be enabled." +
|
|
(uncovered.length
|
|
? '<div class="alert alert-warning mt-2">Roles not yet mapped to ' +
|
|
"theme-builder: " +
|
|
uncovered.join(", ") +
|
|
". Map them under Settings -> Users and security -> Roles before " +
|
|
"enabling layout mode.</div>"
|
|
: ""),
|
|
fields: [
|
|
{
|
|
name: CFG.LAYOUT_MODE,
|
|
label: "Use theme-builder as the page layout",
|
|
type: "Bool",
|
|
default: false,
|
|
sublabel:
|
|
"Hard-blocked unless layout_by_role covers every live role.",
|
|
},
|
|
],
|
|
validator(values) {
|
|
if (values[CFG.LAYOUT_MODE] && uncovered.length) {
|
|
return (
|
|
"Cannot use theme-builder as the page layout yet: assign it to " +
|
|
"every role under 'layout by role' first. Uncovered roles: " +
|
|
uncovered.join(", ") +
|
|
". (This prevents some roles from silently falling back to a " +
|
|
"different layout.)"
|
|
);
|
|
}
|
|
},
|
|
});
|
|
},
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
module.exports = configuration_workflow;
|