feat: Phase 1 — extract the client (web SPA + desktop) to dtoro/oikos-web
Problem: the hexagonal refactor churns the backend tree for nine more phases; the UI delivery stack (web/ SPA, cmd/desktop Wails wrapper, compose/web image) must move to its own repo first so doc/layout rewrites land once on a backend-only tree. Change: - New repo git.hubris.network/dtoro/oikos-web (v0.33.0): web/, desktop/ (updateURL repointed to oikos-web releases), compose/, own CI (web + desktop jobs), own deploy script (CI-green gate, TOCTOU guard, version-tagged images, prune-to-3), own webhook receiver on :9798 + launchd unit, own compose project publishing the same 8091:80. - Cutover executed on mac-mini in order: oikos stack's web service stopped+removed, oikos-web project brought up on 8091; outer Caddy untouched (targets the published port) — serving + Authentik flow + /wails 404 quirk verified post-cutover. - Stripped from oikos: web/, cmd/desktop/, compose/web/, desktop CI workflow, ci.yml web job, Makefile ui/desktop/desktop-package/install targets, the compose web service, oikos-web from deploy.sh's fallback prune list; wails + go-keyring dropped from go.mod, vendor synced. - README / CONTRIBUTING / AGENTS.md / .agents dev+operations docs now point at the new repo; mbse + mascot design docs carry a path note. Risk: production SPA serving depends on the new pipeline now; rollback is versioned-image re-up of the old web service from a pre-split checkout (port 8091). Desktop builds installed before the split still check dtoro/oikos releases — one manual reinstall, noted in the oikos-web release notes. Verification: go vet, make test (race), make generate-check, golangci (no new findings; baseline down 400→365); post-cutover curls — localhost:8091 200, /wails/runtime.js 404, outer Caddy 302 Authentik.
This commit is contained in:
261
web/node_modules/graphology-layout-forceatlas2/helpers.js
generated
vendored
Normal file
261
web/node_modules/graphology-layout-forceatlas2/helpers.js
generated
vendored
Normal file
@@ -0,0 +1,261 @@
|
||||
/**
|
||||
* Graphology ForceAtlas2 Helpers
|
||||
* ===============================
|
||||
*
|
||||
* Miscellaneous helper functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constants.
|
||||
*/
|
||||
var PPN = 10;
|
||||
var PPE = 3;
|
||||
|
||||
/**
|
||||
* Very simple Object.assign-like function.
|
||||
*
|
||||
* @param {object} target - First object.
|
||||
* @param {object} [...objects] - Objects to merge.
|
||||
* @return {object}
|
||||
*/
|
||||
exports.assign = function (target) {
|
||||
target = target || {};
|
||||
|
||||
var objects = Array.prototype.slice.call(arguments).slice(1),
|
||||
i,
|
||||
k,
|
||||
l;
|
||||
|
||||
for (i = 0, l = objects.length; i < l; i++) {
|
||||
if (!objects[i]) continue;
|
||||
|
||||
for (k in objects[i]) target[k] = objects[i][k];
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function used to validate the given settings.
|
||||
*
|
||||
* @param {object} settings - Settings to validate.
|
||||
* @return {object|null}
|
||||
*/
|
||||
exports.validateSettings = function (settings) {
|
||||
if ('linLogMode' in settings && typeof settings.linLogMode !== 'boolean')
|
||||
return {message: 'the `linLogMode` setting should be a boolean.'};
|
||||
|
||||
if (
|
||||
'outboundAttractionDistribution' in settings &&
|
||||
typeof settings.outboundAttractionDistribution !== 'boolean'
|
||||
)
|
||||
return {
|
||||
message:
|
||||
'the `outboundAttractionDistribution` setting should be a boolean.'
|
||||
};
|
||||
|
||||
if ('adjustSizes' in settings && typeof settings.adjustSizes !== 'boolean')
|
||||
return {message: 'the `adjustSizes` setting should be a boolean.'};
|
||||
|
||||
if (
|
||||
'edgeWeightInfluence' in settings &&
|
||||
typeof settings.edgeWeightInfluence !== 'number'
|
||||
)
|
||||
return {
|
||||
message: 'the `edgeWeightInfluence` setting should be a number.'
|
||||
};
|
||||
|
||||
if (
|
||||
'scalingRatio' in settings &&
|
||||
!(typeof settings.scalingRatio === 'number' && settings.scalingRatio >= 0)
|
||||
)
|
||||
return {message: 'the `scalingRatio` setting should be a number >= 0.'};
|
||||
|
||||
if (
|
||||
'strongGravityMode' in settings &&
|
||||
typeof settings.strongGravityMode !== 'boolean'
|
||||
)
|
||||
return {message: 'the `strongGravityMode` setting should be a boolean.'};
|
||||
|
||||
if (
|
||||
'gravity' in settings &&
|
||||
!(typeof settings.gravity === 'number' && settings.gravity >= 0)
|
||||
)
|
||||
return {message: 'the `gravity` setting should be a number >= 0.'};
|
||||
|
||||
if (
|
||||
'slowDown' in settings &&
|
||||
!(typeof settings.slowDown === 'number' || settings.slowDown >= 0)
|
||||
)
|
||||
return {message: 'the `slowDown` setting should be a number >= 0.'};
|
||||
|
||||
if (
|
||||
'barnesHutOptimize' in settings &&
|
||||
typeof settings.barnesHutOptimize !== 'boolean'
|
||||
)
|
||||
return {message: 'the `barnesHutOptimize` setting should be a boolean.'};
|
||||
|
||||
if (
|
||||
'barnesHutTheta' in settings &&
|
||||
!(
|
||||
typeof settings.barnesHutTheta === 'number' &&
|
||||
settings.barnesHutTheta >= 0
|
||||
)
|
||||
)
|
||||
return {message: 'the `barnesHutTheta` setting should be a number >= 0.'};
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function generating a flat matrix for both nodes & edges of the given graph.
|
||||
*
|
||||
* @param {Graph} graph - Target graph.
|
||||
* @param {function} getEdgeWeight - Edge weight getter function.
|
||||
* @return {object} - Both matrices.
|
||||
*/
|
||||
exports.graphToByteArrays = function (graph, getEdgeWeight) {
|
||||
var order = graph.order;
|
||||
var size = graph.size;
|
||||
var index = {};
|
||||
var j;
|
||||
|
||||
// NOTE: float32 could lead to issues if edge array needs to index large
|
||||
// number of nodes.
|
||||
var NodeMatrix = new Float32Array(order * PPN);
|
||||
var EdgeMatrix = new Float32Array(size * PPE);
|
||||
|
||||
// Iterate through nodes
|
||||
j = 0;
|
||||
graph.forEachNode(function (node, attr) {
|
||||
// Node index
|
||||
index[node] = j;
|
||||
|
||||
// Populating byte array
|
||||
NodeMatrix[j] = attr.x;
|
||||
NodeMatrix[j + 1] = attr.y;
|
||||
NodeMatrix[j + 2] = 0; // dx
|
||||
NodeMatrix[j + 3] = 0; // dy
|
||||
NodeMatrix[j + 4] = 0; // old_dx
|
||||
NodeMatrix[j + 5] = 0; // old_dy
|
||||
NodeMatrix[j + 6] = 1; // mass
|
||||
NodeMatrix[j + 7] = 1; // convergence
|
||||
NodeMatrix[j + 8] = attr.size || 1;
|
||||
NodeMatrix[j + 9] = attr.fixed ? 1 : 0;
|
||||
j += PPN;
|
||||
});
|
||||
|
||||
// Iterate through edges
|
||||
j = 0;
|
||||
graph.forEachEdge(function (edge, attr, source, target, sa, ta, u) {
|
||||
var sj = index[source];
|
||||
var tj = index[target];
|
||||
|
||||
var weight = getEdgeWeight(edge, attr, source, target, sa, ta, u);
|
||||
|
||||
// Incrementing mass to be a node's weighted degree
|
||||
NodeMatrix[sj + 6] += weight;
|
||||
NodeMatrix[tj + 6] += weight;
|
||||
|
||||
// Populating byte array
|
||||
EdgeMatrix[j] = sj;
|
||||
EdgeMatrix[j + 1] = tj;
|
||||
EdgeMatrix[j + 2] = weight;
|
||||
j += PPE;
|
||||
});
|
||||
|
||||
return {
|
||||
nodes: NodeMatrix,
|
||||
edges: EdgeMatrix
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Function applying the layout back to the graph.
|
||||
*
|
||||
* @param {Graph} graph - Target graph.
|
||||
* @param {Float32Array} NodeMatrix - Node matrix.
|
||||
* @param {function|null} outputReducer - A node reducer.
|
||||
*/
|
||||
exports.assignLayoutChanges = function (graph, NodeMatrix, outputReducer) {
|
||||
var i = 0;
|
||||
|
||||
graph.updateEachNodeAttributes(function (node, attr) {
|
||||
attr.x = NodeMatrix[i];
|
||||
attr.y = NodeMatrix[i + 1];
|
||||
|
||||
i += PPN;
|
||||
|
||||
return outputReducer ? outputReducer(node, attr) : attr;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Function reading the positions (only) from the graph, to write them in the matrix.
|
||||
*
|
||||
* @param {Graph} graph - Target graph.
|
||||
* @param {Float32Array} NodeMatrix - Node matrix.
|
||||
*/
|
||||
exports.readGraphPositions = function (graph, NodeMatrix) {
|
||||
var i = 0;
|
||||
|
||||
graph.forEachNode(function (node, attr) {
|
||||
NodeMatrix[i] = attr.x;
|
||||
NodeMatrix[i + 1] = attr.y;
|
||||
|
||||
i += PPN;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Function collecting the layout positions.
|
||||
*
|
||||
* @param {Graph} graph - Target graph.
|
||||
* @param {Float32Array} NodeMatrix - Node matrix.
|
||||
* @param {function|null} outputReducer - A nodes reducer.
|
||||
* @return {object} - Map to node positions.
|
||||
*/
|
||||
exports.collectLayoutChanges = function (graph, NodeMatrix, outputReducer) {
|
||||
var nodes = graph.nodes(),
|
||||
positions = {};
|
||||
|
||||
for (var i = 0, j = 0, l = NodeMatrix.length; i < l; i += PPN) {
|
||||
if (outputReducer) {
|
||||
var newAttr = Object.assign({}, graph.getNodeAttributes(nodes[j]));
|
||||
newAttr.x = NodeMatrix[i];
|
||||
newAttr.y = NodeMatrix[i + 1];
|
||||
newAttr = outputReducer(nodes[j], newAttr);
|
||||
positions[nodes[j]] = {
|
||||
x: newAttr.x,
|
||||
y: newAttr.y
|
||||
};
|
||||
} else {
|
||||
positions[nodes[j]] = {
|
||||
x: NodeMatrix[i],
|
||||
y: NodeMatrix[i + 1]
|
||||
};
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
|
||||
return positions;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function returning a web worker from the given function.
|
||||
*
|
||||
* @param {function} fn - Function for the worker.
|
||||
* @return {DOMString}
|
||||
*/
|
||||
exports.createWorker = function createWorker(fn) {
|
||||
var xURL = window.URL || window.webkitURL;
|
||||
var code = fn.toString();
|
||||
var objectUrl = xURL.createObjectURL(
|
||||
new Blob(['(' + code + ').call(this);'], {type: 'text/javascript'})
|
||||
);
|
||||
var worker = new Worker(objectUrl);
|
||||
xURL.revokeObjectURL(objectUrl);
|
||||
|
||||
return worker;
|
||||
};
|
||||
Reference in New Issue
Block a user